<?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=Maista</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=Maista"/>
	<link rel="alternate" type="text/html" href="http://wiki.fhem.de/wiki/Spezial:Beitr%C3%A4ge/Maista"/>
	<updated>2026-10-28T04:39:08Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung&amp;diff=41336</id>
		<title>SolarForecast - Solare Prognose (PV Erzeugung) und Verbrauchersteuerung</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung&amp;diff=41336"/>
		<updated>2026-10-11T13:05:20Z</updated>

		<summary type="html">&lt;p&gt;Maista: Weitere vertipper korrigiert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Modul&lt;br /&gt;
|ModPurpose=Solarprognose und Verbrauchersteuerung&lt;br /&gt;
|ModType=d&lt;br /&gt;
|ModCmdRef=76_SolarForecast&lt;br /&gt;
|ModFTopic=117864&lt;br /&gt;
|ModForumArea=Solaranlagen&lt;br /&gt;
|ModTechName=76_SolarForecast.pm&lt;br /&gt;
|ModOwner=DS_Starter ({{Link2FU|16933|Forum}}/[[Benutzer Diskussion:DS_Starter|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
[[SolarForecast - Solare Prognose (PV Erzeugung) und Verbrauchersteuerung|SolarForecast]] ist ein integratives Modul zur Gewinnung solarer Vorhersagedaten, deren Verarbeitung und grafischen Darstellung. Desweiteren bietet es die Möglichkeit, in FHEM definierte Verbraucher in einem SolarForecast-Device zu registrieren und eine PV Prognose basierte Steuerung der Verbraucher vom Modul übernehmen zu lassen.&lt;br /&gt;
&lt;br /&gt;
Das Modul ist insbesondere durch folgende Eigenschaften gekennzeichnet:&lt;br /&gt;
[[Datei:sfc1.png|right|thumb|300px|grafische Ansicht SolarForecast]]&lt;br /&gt;
&lt;br /&gt;
::* zur Gewinnung solarer Prognosewerte können die SolCast API, OpenMeteo API, Forecast.Solar API, Victron VRM Portal API oder alternativ DWD Stahlungswerte-Stationen verwendet werden&lt;br /&gt;
&lt;br /&gt;
::* optionale KI Unterstützung der PV-Prognose bei Verwendung von geeigneten Solar-APIs&lt;br /&gt;
&lt;br /&gt;
::* optionale KI Unterstützung der Prognose des Energieverbrauchs der kommenden Stunden&lt;br /&gt;
&lt;br /&gt;
::* es wird sowohl die Erzeugungsprognose als auch eine Verbrauchsprognose sowie SoC Prognose (bei Batterie-Integration) erstellt&lt;br /&gt;
&lt;br /&gt;
::* Wetterdaten werden über DWD Wetter-Stationen oder API integriert. Es können verschiedene APIs zur Gewinnung von Solar- und Wetterdaten kombiniert werden. &lt;br /&gt;
&lt;br /&gt;
::* Sprachensupport EN / DE&lt;br /&gt;
&lt;br /&gt;
::* die Prognosedaten, Wetterdaten, Verbraucherplanungen und die aktuellen Energieflüsse werden in umfangreich anpassbaren integrierten Grafiken dargestellt&lt;br /&gt;
&lt;br /&gt;
::* es wird keine externe SQL-Datenbank benötigt, die Datenhaltung erfolgt in einer Memory basierten Cachedatenbank inkl. einer Filesystempersistenz zur Datensicherung und Wiederherstellung beim FHEM-Restart&lt;br /&gt;
&lt;br /&gt;
::* die Integration von Geräten wie Wechselrichter, Energy Meter, Batterien, Wetterstationen oder Verbrauchern ist offen und universell gestaltet und bietet dem Anwender maximale Freiheiten bei der Einrichtung seines individuellen Solardatensystems.&lt;br /&gt;
&lt;br /&gt;
::* eine Integration von bis zu 4 Inverter und Smartloader (DC-DC Batterieladegeräte) ist möglich&lt;br /&gt;
&lt;br /&gt;
::* eine Integration von bis zu 3 nicht PV-Energieerzeugern wie BHKW, Windrädern oder Notstromaggregaten ist möglich&lt;br /&gt;
&lt;br /&gt;
::* eine integrierte und umfangreich anpassbare Verbrauchersteuerung vereint die PV Prognose basierte Einplanung der Verbraucher mit der Möglichkeit die Verbraucher durch das Modul schalten zu lassen und dadurch auf PV Erzeugungsschwankungen automatisch dynamisch zu reagieren&lt;br /&gt;
&lt;br /&gt;
::* Einbindung von bis zu 3 Batteriespeichersystemen&lt;br /&gt;
&lt;br /&gt;
::* Bereitstellung von Leitwerten zur optimalen Einstellung/Steuerung von Batteriespeichersystemen&lt;br /&gt;
&lt;br /&gt;
::* trotz der hohen Komplexität wird dem Anwender durch eine &amp;quot;Guided Procedure&amp;quot; bei der Gerätedefinition der Einstieg erleichtert und damit ein optimales Benutzererlebnis geboten&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Abgrenzung:&#039;&#039;&#039; Das Modul 76_SolarForecast ist nicht zu verwechseln mit der SQL-basierten (DbLog) Prognose-Lösung mit Kostal Plenticore Wechselrichtern, die auf der eigenen Seite &#039;&#039;&#039;[[Kostal_Plenticore_10_Plus]]&#039;&#039;&#039; behandelt wird. Diese Lösung beschreibt kein monolithisches Modul, sondern basiert auf einer orchestrierbaren Zusammenstellung individueller Perl Programmbausteine. &lt;br /&gt;
&lt;br /&gt;
Im vorliegenden Wiki-Beitrag wird ausschließlich das Modul 76_SolarForecast behandelt.&lt;br /&gt;
&lt;br /&gt;
== Rahmenbedingungen und Voraussetzungen ==&lt;br /&gt;
&lt;br /&gt;
Das Wiki gibt allgemeingültige und teilweise sehr spezifische bzw. tiefgehende Informationen und Handlungsempfehlungen zum SolarForecast Modul. Die dargestellten Informationen beziehen sich auf den zum Zeitpunkt der Wiki-Erstellung vorhandenen Entwicklungsstand des Moduls. Durch die stetige Weiterentwicklung können sich Abweichungen zum beschriebenen Inhalt ergeben oder zur Obsoleszenz dieser Inhalte führen. &lt;br /&gt;
&lt;br /&gt;
Vergleiche deshalb die Informationen immer mit der aktuellen Befehls-Referenz zum Modul!&lt;br /&gt;
&lt;br /&gt;
== Definition ==&lt;br /&gt;
Ein SolarForecast Device wird mit dem Befehl&lt;br /&gt;
&lt;br /&gt;
 define &amp;lt;Name&amp;gt; SolarForecast &lt;br /&gt;
&lt;br /&gt;
angelegt. Nach der Definition wird der User durch einen Dialog geführt, der einige unerlässliche Einstellungen abfragt und in den entsprechenden Attributen und Readings persistiert. Alle Attribute und Readings die eine Einstellung der Anlage bewirken, sind mit dem Präfix &amp;quot;setup&amp;quot; versehen. &lt;br /&gt;
&lt;br /&gt;
Die Verwendung von setup-Readings gestattet es die Anlagenparameter dynamisch im Betrieb zu verändern. So kann mit &lt;br /&gt;
&lt;br /&gt;
 set &amp;lt;Name&amp;gt; setupStringAzimuth   bzw.&lt;br /&gt;
 set &amp;lt;Name&amp;gt; setupStringDeclination &lt;br /&gt;
&lt;br /&gt;
die Ausrichtung und der Neigungswinkel der PV-Module ständig angepasst werden, was zum Beispiel bei einer dem Sonnenstand nachgeführten Anlage von Bedeutung ist.&lt;br /&gt;
&lt;br /&gt;
Die abgefragten Einstellungen während des Dialoges sind ausführlich in den entsprechenden Attributen bzw. Set-Kommandos erläutert. Die benötigten Informationen sind anhängig von der gewählten Prognose-API und können im Umfang variieren.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2024-09-21 213257.png|right|thumb|400px|Anlagenprüfung über Drucktaste in der Kopfgrafik]]&lt;br /&gt;
&lt;br /&gt;
Sobald alle verlangten Einstellungen vorgenommen sind, sollte eine Anlagenprüfung mit &lt;br /&gt;
&lt;br /&gt;
 set &amp;lt;Name&amp;gt; plantConfiguration check&lt;br /&gt;
&lt;br /&gt;
oder über die angebotene Drucktaste in der Grafik durchgeführt werden. Es wird eine Plausibilitätsprüfung vorgenommen und das Ergebnis sowie eventuelle Hinweise bzw. Fehler ausgegeben.&lt;br /&gt;
Die Prüfung kann beliebig wiederholt werden und sollte sich bei jeder Einstellungsänderung der Anlage durchgeführt werden. Dadurch wird die Wahrscheinlichkeit von fehlerhaften Einstellungen minimiert.&lt;br /&gt;
&lt;br /&gt;
Neben den grundlegenden Einstellungen können im Device weitere sekundäre Anlagenkomponenten wie Batteriesystem(e) (Attribut setupBatteryDev1 - setupBatteryDev3), weitere Wetter-Devices (Attribut setupWeatherDev1 - setupWeatherDev3) oder sonstige Erzeuger (z.B. BHKW, Winderzeugung, Notstromaggregat) integriert werden (Attribut setupOtherProducer01 - setupOtherProducer03).&lt;br /&gt;
&lt;br /&gt;
Die verlangten Parameter der Anlage werden in der Online-Hilfe umfassend beschrieben und deren Funktion erschließt sich zum größten Teil selbst. Dennoch soll nachfolgend auf einige Punkte im Zusammenhang der Einrichtung eingegangen werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Hinweise zur Struktur der Attribute ===&lt;br /&gt;
&lt;br /&gt;
Durch die umfangreichen Funktionen des Moduls würde bei Nutzung der im FHEM herkömmlich vorhandenen Attributstruktur die Anzahl der benötigten Attribute extrem stark steigen und nicht sinnvoll genutzt werden können. Deshalb gibt es neben den &#039;&#039;gewöhnlichen&#039;&#039; Attributen mit einfachen Werteauswahlmöglichkeiten oder Eingaben (z.B. ctrlDebug, ctrlSpecialReadings) sogenannte &#039;&#039;zusammengesetzte&#039;&#039; Attribute, deren Inhalt durch &#039;&#039;&#039;Schlüssel=Wert Paare&#039;&#039;&#039; gebildet wird und dadurch deutlich mehr Funktionen und Informationen transportieren als ein gewöhnliches Attribut.&lt;br /&gt;
&lt;br /&gt;
Für zusammengesetzte Attribute besteht die zusätzliche Möglichkeit, gewünschte Änderungen der Schlüssel=Wert Paare selektiv vornehmen zu können, ohne das gesamte Attribut aufrufen und ändern zu müssen. Die Vorgang, der vor allem für programmtechnische Manipulationen gedacht ist, kann durch eine Set-Funktion ausgeführt werden:&lt;br /&gt;
&lt;br /&gt;
 set &amp;lt;Name&amp;gt; attrKeyVal &amp;lt;Attribut&amp;gt; [&amp;lt;Gerät&amp;gt;] &amp;lt;Schlüssel=Wert&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiele für zusammengesetzte Attribute sind:&lt;br /&gt;
&lt;br /&gt;
* aiControl&lt;br /&gt;
* plantControl&lt;br /&gt;
* setup* Attribute&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Funktionen der Attribute werden durch einen Präfix geclustert und so inhaltlich, aber vor allem auch in der Attribute Drop-Down Liste, strukturiert dargestellt.&lt;br /&gt;
&lt;br /&gt;
Die Bedeutung der &#039;&#039;&#039;Präfixe&#039;&#039;&#039; sind:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ai&#039;&#039;&#039; - Steuerungsfunktionen für KI (z.B. aiControl)&lt;br /&gt;
* &#039;&#039;&#039;consumer&#039;&#039;&#039; - Registrierung und Einstellungen für Verbraucher (z.B. consumer02, consumerControl)&lt;br /&gt;
* &#039;&#039;&#039;ctrl&#039;&#039;&#039; - Steuerungsfunktion allgemeiner Art (z.B. ctrlDebug, ctrlSpecialReadings, ctrlUserExitFn)&lt;br /&gt;
* &#039;&#039;&#039;flowGraphic&#039;&#039;&#039; - Einstellungen für die Energieflußgrafik (z.B. flowGraphicControl)&lt;br /&gt;
* &#039;&#039;&#039;graphic&#039;&#039;&#039; - Einstellung für die Grafik allgemein (z.B. graphicSelect, graphicControl)&lt;br /&gt;
* &#039;&#039;&#039;graphicBeam&#039;&#039;&#039; -  Einstellungen bestimmte Balkeneigenschaften in der Balkengrafik (z.B. graphicBeamHeightLevel1)&lt;br /&gt;
* &#039;&#039;&#039;plant&#039;&#039;&#039; - übergreifende Einstellungen betreffend der gesamten PV-Anlage bzw. des SolarForecast-Devices (z.B. plantControl)&lt;br /&gt;
* &#039;&#039;&#039;setup&#039;&#039;&#039; - Registrierung von Geräten in der Gesamtanlage und Einstellung deren Eigenschaften (Inverter, Zähler, Batterien usw.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Einrichtung der Wechselrichter mit setupInverterDevXX ===&lt;br /&gt;
&lt;br /&gt;
Mit den Attributen setupInverterDev01 bis setupInverterDevXX werden die vorhandenen Wechselrichter der Anlage registriert.&lt;br /&gt;
Das Modul unterscheidet verschiedene Wechselrichter-Typen, die sich durch ihre Arbeitsweise innerhalb der Anlage unterscheiden. Die Schlüssel=Wert Paare in den Attributen können mehrzeilig organisiert werden. Das erleichtert die Übersicht wenn viele dieser Parameter eingegeben werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;PV-Wechselrichter: Es ist der Standard Wechselrichter in einer PV-Anlage. An ihn sind die Solarzellen bzw. Strings angeschlossen. Die zugeordneten Strings können mit dem Schlüssel &#039;&#039;&#039;strings&#039;&#039;&#039; zugeordnet werden. Ohne diese Angabe werden diesem Gerät alle definierten Strings (siehe Attribut &#039;&#039;setupInverterStrings&#039;&#039;) zugeordnet. Der Wechselrichter liefert seine Energie in das Hausnetz. Alternativ kann mit der Angabe &#039;&#039;&#039;feed=grid&#039;&#039;&#039; die Funktion des Wechselrichters geändert werden. Diese Angabe sagt aus, dass dieser Wechselrichter ausschließlich in das öffentliche Netz einspeist.&lt;br /&gt;
&lt;br /&gt;
Hier ein Beispiel-Setup eines PV-Wechselrichters (SMA STP):&lt;br /&gt;
&lt;br /&gt;
 STP_5000 pvIn=string_1_pdc:kW pvOut=total_pac:kW etotal=etotal:kWh capacity=5000 strings=Süddach asynchron=1 limit=100&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Solar-Ladegeräte: Solar-Ladegeräte sind DC-DC Wandler und liefern die Energie der angeschlossenen Solarzellen nicht in das Wechselstromnetz, sondern laden direkt eine Batterie bzw. versorgen einen Batteriewechselrichter auf der Gleichstromseite. Die Funktion als Solar-Ladegerät wird mit &#039;&#039;&#039;feed=bat&#039;&#039;&#039; aktiviert, die relevanten Strings können ebenfalls mit dem Schlüssel &#039;&#039;&#039;strings&#039;&#039;&#039; zugeordnet werden. Ein Beispiel eines Solar-Ladegerätes ist ein Victron SmartSolar MPPT. &lt;br /&gt;
&lt;br /&gt;
Ein Beispiel für das Setup eines Solar-Ladegeräts (SmartSolar Charger MPPT):&lt;br /&gt;
&lt;br /&gt;
 MQTT2_cerboGX_c0619ab34e08_solarcharger_Common pv=Yield_Power_value:W etotal=Yield_System_value:kWh capacity=2080 strings=Schleppdach feed=bat synchron=0 limit=100&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Batterie-Wechselrichter: Dieses Gerät hat keine angeschlossenen Solarzellen und arbeitet als DC-AC bzw. AC-DC Wandler zwischen einer Batterie (=Gleichstromquelle) und dem Wechselstrom-Hausnetz. Die Funktion als Batterie-Wechselrichter wird mit der Angabe &#039;&#039;&#039;strings=none&#039;&#039;&#039; aktiviert. Die Schlüssel &#039;&#039;etotal&#039;&#039; und &#039;&#039;pv&#039;&#039; können bei einem Batterie-Wechselrichter ohne zugeordnete Solarzellen nicht gesetzt werden. Ein Beispiel eines Batterie-Wechselrichter ist der Victron MultiPlus II.&lt;br /&gt;
&lt;br /&gt;
Ein Setup-Beispiel für einen Batterie-Wechselrichter (Victron MultiPlus II):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dc2ac=DC_IN:W&lt;br /&gt;
ac2dc=DC_OUT:W&lt;br /&gt;
capacity=7200&lt;br /&gt;
strings=none&lt;br /&gt;
icon=inverter@darkorange:inverter@grey&lt;br /&gt;
asynchron=0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Eigenschaften des Wechselrichters werden durch eine Reihe von &amp;lt;Schlüssel=Wert&amp;gt; Paaren festgelegt. Auf einige dieser Paramter soll hier eingegangen werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Ausgewählte Schlüssel=Wert Paare ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;pvIn=&amp;lt;Readingname&amp;gt;:&amp;lt;Einheit&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
	&lt;br /&gt;
Dem Schlüssel &#039;&#039;pvIn&#039;&#039; wird ein Reading und dessen Einheit (W,kW) des Wechselrichter-Device zugeordnet, welches die aktuell zugeführte PV-Leistung bereitstellt. Der Schlüssel ist optional und dient in erster Linie dazu den entsprechenden Input-Wert in der Flußgrafik anzuzeigen sofern man das Attribut flowGraphicControl-&amp;gt;showGenerators=1 setzt. Dadurch ist auch der Eigenverbrauch des Inverters bzw. dessen Wandlungsverlust visuell abschätzbar.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;pvOut=&amp;lt;Readingname&amp;gt;:&amp;lt;Einheit&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
	&lt;br /&gt;
Dem Schlüssel &#039;&#039;pvOut&#039;&#039; wird ein Reading und dessen Einheit (W,kW) des Wechselrichter-Device zugeordnet, welches die aktuell erzeugte Leistung als positiven Wert liefert. Für einen PV-Wechselrichter (DC-&amp;gt;AC) oder Solar-Ladegerät (DC-&amp;gt;DC) ist es die erzeugte PV-Leistung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ac2dc=&amp;lt;Readingname&amp;gt;:&amp;lt;Einheit&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dieser Schlüssel ist nur für einen Batterie-Wechselrichter setzbar. Das Reading liefert die aktuelle Leistung, die der Wechselrichter vom Hausnetz in Richtung Batterie (AC-&amp;gt;DC) wandelt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dc2ac=&amp;lt;Readingname&amp;gt;:&amp;lt;Einheit&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dieser Schlüssel ist nur für einen Batterie-Wechselrichter setzbar. Das Reading liefert die aktuelle Leistung, die der Wechselrichter aus einer Gleichstromquelle, d.h. einer Batterie oder einem Solar-Ladegerät, in Richtung des Hausnetzes (AC) wandelt . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;capacity=&amp;lt;max. WR-Leistung&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In dem Schlüssel &#039;&#039;capacity&#039;&#039; wird die maximal mögliche Leistung in Watt (ohne Einheit) angegeben, die der Wechselrichter lt. seinem Datenblatt in der Lage ist zu leisten. &lt;br /&gt;
&lt;br /&gt;
Die Angabe &#039;&#039;capacity&#039;&#039; hat in erster Linie die Aufgabe, die max. mögliche PV-Leistung für die Prognose zu begrenzen. Oft sind die installierten Peak-Leistungen der PV-Module höher als die angeschlossene Wechselrichter-Leistung bzw. kommt es vor, dass die KI / (korrigierte) API-Prognose über der maximal möglichen Wechselrichter-Leistung liegt. In diesen Fällen wird die Prognose auf die angegebene &#039;&#039;capacity&#039;&#039; begrenzt.&lt;br /&gt;
&lt;br /&gt;
Der Wert in diesem Schlüssel kann, wie andere Schlüssel auch, dynamisch zur Laufzeit mit dem Set-Befehl &amp;quot;[[#Hinweise zur Struktur der Attribute|set &amp;lt;Name&amp;gt; attrKeyVal ...]]&amp;quot; geändert werden. Ein Beispiel zur Anwendung ergibt sich aus folgendem Szenario.&lt;br /&gt;
&lt;br /&gt;
Gegeben sei eine Anlage die aus Solarzellen (1300 W Peak) mit einem Solar-Ladegerät mit max. 1800 W Leistung, einer Batterie und einem Batterie-Wechselrichter besteht. Die Anlage versorgt nur das Hausnetz. Eine Netzeinspeisung ist nicht vorgesehen oder nicht erlaubt.  &lt;br /&gt;
&lt;br /&gt;
Nehmen wir an, es ist ein Tag voller Sonnenschein prognostiziert und die Batterie ist zunächst entladen. Der Haushalt verbraucht 300 W. Dann würden die PV-Module Module ihre volle Leistung von 1300 W Peak leisten können, die sich auch in der Balken-Vorhersage niederschlägt. Die Leistung wird nicht begrenzt, weil:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* sie niedriger ist als die nominale und angegebene Wechselrichter Kapazität von &#039;&#039;capacity=1800&#039;&#039;&lt;br /&gt;
* die erzeugte Energie anteilig für die Verorgung des Hauses und die Aufladung der Batterie verwendet wird&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Anders verhält es sich wenn nach einer gewissen Zeit die Batterie voll ist und weiterhin volle PV Leistung zur Verfügung steht. In diesem Fall würde der Haushalt seine benötigte Leistung von 300 W abnehmen, aber das Solar-Ladegerät kann keine weitere Leistung mehr abgeben, da die Batterie bereits voll geladen ist, d.h. die Anlagensteuerung würde die PV-Anlage abregeln. In diesem Fall, wenn es einen längeren Zeitraum betrifft, muß auch die Prognose PV-Energie auf 300 Wh (bzw. den durchschnittlichen Energieverbrauch des Hauses pro Stunde) begrenzt werden, damit die PV-Prognose nach unten angepasst wird und so eine realitätsnahere Prognose ermöglicht wird. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;icon=&amp;lt;aktiv&amp;gt;[@&amp;lt;Farbe&amp;gt;][:&amp;lt;inaktiv&amp;gt;[@&amp;lt;Farbe&amp;gt;]]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Jeder Wechselrichter wird im Standard durch ein Icon getrennt nach Tag und Nacht, d.h. je nach Aktiv-Status und Inaktiv-Status, symbolisiert.&lt;br /&gt;
&lt;br /&gt;
;Tag bzw. Aktivität: Für Wechselrichter mit angeschlossenen PV-Modulen wird ein entsprechend gefärbtes Sonnensymbol im Standard verwendet. Batterie-Wechselrichter verwenden ein gefärbtes Invertersymbol.&lt;br /&gt;
&lt;br /&gt;
;Nacht bzw. Inaktivität: Für Wechselrichter mit angeschlossenen PV-Modulen wird ein entsprechend gefärbtes Symbol der aktuellen Mondphasen im Standard verwendet. Batterie-Wechselrichter verwenden ein ausgegrautes Invertersymbol.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wie angegeben, kann man für Tag und Nacht jeweils ein Wunsch-Icon, wenn gewünscht mit einer alternativen Färbung, auswählen.&lt;br /&gt;
&lt;br /&gt;
 icon=inverter@darkorange:inverter@gray&lt;br /&gt;
&lt;br /&gt;
Soll nur das Icon für die Nacht bzw. Inaktivät geändert werden, kann dies in dieser Form angegeben werden:&lt;br /&gt;
&lt;br /&gt;
 icon=:inverter@gray  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(beachte den führenden &#039;:&#039;)&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Definition von Hybrid-Wechselrichtern  ====&lt;br /&gt;
&lt;br /&gt;
Zur Zeit der Erstellung dieses Abschnittes ist es in der SolarForecast Version 1.58.x nicht möglich, einen Hybridwechselrichter nativ zu definieren. Als Workaround wird eine passende Kombination aus PV-Wechselrichter und Batterie-Device oder einer Kombination aus PV-Wechselrichter + Batterie-Wechselrichter und Batterie-Device erstellt.&lt;br /&gt;
&lt;br /&gt;
Bei allen benutzten Methoden ist es sehr wichtig!, dass die geforderten Inhalte der jeweilige Attributschlüssel beachtet und eingehalten werden. So ist zum Beispiel die Angabe von:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;pvOut&#039;&#039;&#039; - Ein Reading, welches die aktuelle Leistung aus PV-Erzeugung, die an das Hausnetz oder öffentliche Netz geliefert wird, bereitstellt. Es wird ein positiver numerischer Wert erwartet.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
bei einem PV-Wechselrichter ein Reading welches ausschließlich die Leistung liefert, die von den Solarzellen-Generatoren erzeugt wird. Elemente von Batterieleistungen oder Gridbestandteile dürfen hier nicht enthalten sein. Sind in den Gerätemodulen diese Readings in dieser Form nicht enthalten, bietet es sich an, userReadings zur Erstellung von zusätzlichen Readings in den Quellendevices zu nutzen um den nötigen Input für SolarForecast bereitzustellen. &lt;br /&gt;
&lt;br /&gt;
So wird zum Beispiel bei einem 	Batterie-Wechselrichter gefordert, dass die Readings &#039;&#039;&#039;ac2dc&#039;&#039;&#039; (AC-&amp;gt;DC-Leistung Hausnetz zur Batterie) und &#039;&#039;&#039;dc2ac&#039;&#039;&#039; (DC-&amp;gt;AC-Leistung (Batterie zum Hausnetz) &#039;&#039;&#039;jeweils als als positiver Wert&#039;&#039;&#039; anzugeben ist. Manche Batterie-Devices stellen allerdings nur ein Reading zur Verfügung, welches vorzeichenbehaftet die Leistungen in die Batterie bzw. aus der Batterie heraus liefert. Mit einem userReadings Attribut kann aus diesem Reading zwei neue Readings erzeugt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr &amp;lt;Name&amp;gt; userReadings  BatIn:DC_Power_value.* {&lt;br /&gt;
                          my $pwr = ReadingsVal ($name, &#039;DC_Power_value&#039;, 0);&lt;br /&gt;
                          $pwr    = $pwr &amp;gt; 0 ? $pwr : 0;&lt;br /&gt;
                          $pwr&lt;br /&gt;
                          },&lt;br /&gt;
                          BatOut:DC_Power_value.* {&lt;br /&gt;
                          my $pwr = ReadingsVal ($name, &#039;DC_Power_value&#039;, 0);&lt;br /&gt;
                          $pwr    = $pwr &amp;lt; 0 ? - $pwr : 0;&lt;br /&gt;
                          $pwr&lt;br /&gt;
                          },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ist das Quellenreading &#039;&#039;DC_Power_value&#039;&#039; positiv, stellt der Wert AC-&amp;gt;DC-Leistung dar und wird als neues Reading BatIn bereitgestellt. Mit einem negativen Vorzeichen ist es eine DC-&amp;gt;AC-Leistung und wird in dem neuen Reading BatOut &#039;&#039;&#039;ebenfalls als positiver Wert&#039;&#039;&#039; bereitgestellt. Auch hier gilt der Grundsatz, dass zum Beispiel BatOut nur die von der Batterie gelieferte Energie und keinen Mix aus Batterie- und PV-Energie enthalten darf.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
===== Integration eines DEYE SUN-12K-SG04LP3-EU =====&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2025-09-23 203955.png|right|thumb|400px|DEYE SUN-12K-SG04LP3-EU Grundlegende Systemarchitektur]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der DEYE vereint wie wohl alle bzw. die meisten Hybrid-Wechselrichter die Anschlüsse:&lt;br /&gt;
&lt;br /&gt;
* Eingang Solar-Strings&lt;br /&gt;
* Anschluß Batteriespeicher&lt;br /&gt;
* AC-Anschluß öffnetliches Netz&lt;br /&gt;
* AC-Anschluß Ersatzlast (wird bei Netzausfall weiter versorgt)&lt;br /&gt;
* AC-Anschluß Notstromgenerator bzw. netzgekoppelter anderer Wechselrichter (hier ist ein Growatt Micro-Wechselrichter angeschlossen)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Für die Integration werden die setup-Attribute durch das FHEM Device &#039;&#039;Deye_Inverter&#039;&#039; besetzt:&lt;br /&gt;
&lt;br /&gt;
* setupInverterStrings zur Definition der vorhandenen Solarstrings&lt;br /&gt;
* setupInverterDev01 zur Definition der Inverteranschlüsse und Eigenschaften&lt;br /&gt;
* setupBatteryDev01 integriert die Batterie&lt;br /&gt;
* setupMeterDev liefert die Daten für Netzbezug und Netzeinspeisung&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das nachfolgend verwendete Device &#039;&#039;Deye_Inverter&#039;&#039; ist ein MQTT-Device. Es bekommt Daten vom Deye-Hybridwechselrichter per MQTT und sendet Einstellungen zum Deye, bspw. maximaler Lade/Entladestrom des Akkus, Laden des Akkus aus dem Netz, Ein- und Ausschalten des Micro-Inverter-Ports.&lt;br /&gt;
Das Reading &#039;&#039;Deye_Growatt_power&#039;&#039; im Schlüssel &#039;&#039;pvOut&#039;&#039; ist eine Addition aus den Daten des Deye WR und des angeschlossenen Growatt Micro-Wechselrichters.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr &amp;lt;Name&amp;gt; setupInverterStrings Sueddach,Garagendach&lt;br /&gt;
attr &amp;lt;Name&amp;gt; setupInverterDev01 Deye_Inverter pvOut=Deye_Growatt_power:W capacity=15200 etotal=total_pv_production:kWh&lt;br /&gt;
attr &amp;lt;Name&amp;gt; setupBatteryDev01 Deye_Inverter pin=-pout pout=battery_output_power:W intotal=total_charge_of_the_battery:kWh outtotal=total_discharge_of_the_battery:kWh cap=15200 charge=SOC_jkbms&lt;br /&gt;
attr &amp;lt;Name&amp;gt; setupMeterDev Deye_Inverter gcon=total_grid_power:W contotal=total_energy_bought:kWh gfeedin=-gcon feedtotal=total_energy_sold:kWh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;setupInverterStrings&#039;&#039; benennt alle vorhandenen Solarstrings. Werden mehrere Inverter definiert, kann mit dem hier nicht verwendeten Schlüssel &#039;&#039;strings&#039;&#039; eine Zuordnung der Strings zum angeschlossenen Inverter vorgenommen werden.&lt;br /&gt;
&lt;br /&gt;
Im Attribut &#039;&#039;setupInverterDev01&#039;&#039; ist der allgemeine Schlüssel &#039;&#039;capacity&#039;&#039; zur Festlegung der Inverterleistung von 15200 Watt gesetzt. Die spezifischen Schlüssel &#039;&#039;pvOut&#039;&#039; und &#039;&#039;etotal&#039;&#039; teilen dem Modul die aktuell erzeugte PV-Leistung sowie die gesamte erzeugte PV-Energie mit. Letzteres dient unter anderem dazu die stündlich real erzeugte PV-Energie festzuhalten und mit der Prognose zu vergleichen. Die in den schlüsseln hinterlegten dürfen keine Batterie- oder Netzanteile enthalten.&lt;br /&gt;
&lt;br /&gt;
Das Attr &#039;&#039;setupBatteryDev01&#039;&#039; implementiert alle relevanten Batteriewerte. Das Reading &#039;&#039;battery_output_power&#039;&#039; im Schlüssel &#039;&#039;pout&#039;&#039; liefert den Batterie-Output als positiven Wert. Als Besonderheit kann der Wert &#039;&#039;pin&#039;&#039;, die Batterie-Ladeleistung, den Wert des Readings in &#039;&#039;pout&#039;&#039; übernehmen wenn dieser Wert ein negatives Vorzeichen hat. Die Schlüssel &#039;&#039;intotal&#039;&#039; und &#039;&#039;outtotal&#039;&#039; liefern die summierten Totalwerte für Batterie Ladung bzw. Entladung. Die Kapazität &#039;&#039;cap&#039;&#039; wird für verschiedene Aspekte der SoC- und Ladesteuerung verwendet. &lt;br /&gt;
&lt;br /&gt;
Abschließend liefern die angegebenen Readings in den Schlüsseln des Attributes &#039;&#039;setupMeterDev&#039;&#039; alle notwendigen Werte des Netzbezugs und der Netzeinspeisung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nachfolgende Links liefern &#039;&#039;&#039;weitere Infos&#039;&#039;&#039; wie man Daten aus dem Deye WR ausliest und Einstellungen des Deye WR verändert:&lt;br /&gt;
&lt;br /&gt;
* https://github.com/klatremis/esphome-for-deye&lt;br /&gt;
* https://github.com/philipphenkel/esphome-config&lt;br /&gt;
* https://github.com/bagges/deye-esp32-bridge&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Für eine weiterführende Automation soll der Akku netzdienlich in der Mittagszeit geladen werden. Dazu wurde durch den Anwender folgendes userReadings &#039;&#039;MaxBattCharge_Request&#039;&#039; im Device &#039;&#039;Deye_Inverter&#039;&#039; für den maximalen Ladestrom definiert (bei 90% SOC und bei 100% SOC):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MaxBattCharge_Request:SOC_jkbms.* {&lt;br /&gt;
                                    if ((ReadingsNum(&#039;mySolarForecast&#039;,&#039;RestOfDayPVforecast&#039;,&#039;&#039;)&lt;br /&gt;
                                         - ReadingsNum(&#039;mySolarForecast&#039;,&#039;special_todayConForecastTillSunset&#039;,&#039;&#039;)&lt;br /&gt;
                                         - (90-ReadingsNum(&#039;JK_BMS&#039;,&#039;capacity_remaining&#039;,&#039;&#039;))/100*310*51.2) &amp;lt; 400&lt;br /&gt;
                                         and ReadingsAge(&#039;JK_BMS&#039;,&#039;capacity_full_timestamp&#039;,&#039;&#039;) &amp;lt; 561600)&lt;br /&gt;
                                    {100}&lt;br /&gt;
                                    elsif ((ReadingsNum(&#039;mySolarForecast&#039;,&#039;RestOfDayPVforecast&#039;,&#039;&#039;)&lt;br /&gt;
                                            - ReadingsNum(&#039;mySolarForecast&#039;,&#039;special_todayConForecastTillSunset&#039;,&#039;&#039;)&lt;br /&gt;
                                            - (100-ReadingsNum(&#039;JK_BMS&#039;,&#039;capacity_remaining&#039;,&#039;&#039;))/100*310*51.2) &amp;lt; 400&lt;br /&gt;
                                            and ReadingsAge(&#039;JK_BMS&#039;,&#039;capacity_full_timestamp&#039;,&#039;&#039;) &amp;gt;= 561600)&lt;br /&gt;
                                    {100}&lt;br /&gt;
                                    elsif ((ReadingsNum(&#039;mySolarForecast&#039;,&#039;RestOfDayPVforecast&#039;,&#039;&#039;)&lt;br /&gt;
                                            - ReadingsNum(&#039;mySolarForecast&#039;,&#039;special_todayConForecastTillSunset&#039;,&#039;&#039;)&lt;br /&gt;
                                            - (90-ReadingsNum(&#039;JK_BMS&#039;,&#039;capacity_remaining&#039;,&#039;&#039;))/100*310*51.2) &amp;gt;= 400&lt;br /&gt;
                                            and ReadingsAge(&#039;JK_BMS&#039;,&#039;capacity_full_timestamp&#039;,&#039;&#039;) &amp;lt; 561600)&lt;br /&gt;
                                    {ceil ((90-ReadingsNum(&#039;JK_BMS&#039;,&#039;capacity_remaining&#039;,&#039;&#039;))/100*310/3.5)}&lt;br /&gt;
                                    elsif ((ReadingsNum(&#039;mySolarForecast&#039;,&#039;RestOfDayPVforecast&#039;,&#039;&#039;)&lt;br /&gt;
                                            - ReadingsNum(&#039;mySolarForecast&#039;,&#039;special_todayConForecastTillSunset&#039;,&#039;&#039;)&lt;br /&gt;
                                            - (100-ReadingsNum(&#039;JK_BMS&#039;,&#039;capacity_remaining&#039;,&#039;&#039;))/100*310*51.2) &amp;gt;= 400&lt;br /&gt;
                                            and ReadingsAge(&#039;JK_BMS&#039;,&#039;capacity_full_timestamp&#039;,&#039;&#039;) &amp;gt;= 561600)&lt;br /&gt;
                                    {ceil ((100-ReadingsNum(&#039;JK_BMS&#039;,&#039;capacity_remaining&#039;,&#039;&#039;))/100*310/3.0)}&lt;br /&gt;
                                  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das userReading wird in einer Automation benutzt, um den maximalen Ladestrom einzustellen; Ladebeginn bei ausreichend Sonne ist ab 11:30 eingestellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
===== Integration eines Fronius Symo GEN24 10.0 Plus mit (virtuellen) Batterie-Wechselrichter =====&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2025-10-04 162422.png|right|thumb|400px|Flußgrafik mit eingebauten Hybrid-Wechselrichter]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Integration des Wechselrichters Fronius Symo GEN24 10.0 Plus benötigt zunächst eine Anbindung in FHEM, was mit dem Modul 98_fronius.pm vorgenommen wurde.&lt;br /&gt;
&lt;br /&gt;
Das Ziel der Kurzdokumentation ist neben der Darstellung eines Hybridwechselrichters aufzuzeigen, wie man den Wandlungsverlust eines PV-Wechselrichters (pvIn – pvOut) in Näherung visualisieren kann.  &lt;br /&gt;
&#039;&#039;&#039;pvIn&#039;&#039;&#039; ist dabei die Summe der Produkte aus den DC Strom- und Spannungswerten der einzelnen Strings (hier 2109 W), &#039;&#039;&#039;pvOut&#039;&#039;&#039; (hier 2065 W) ist die an den Inverterknoten (hier 1105 W) plus die an die Batterie abgegebene Leistung (hier 960 W). Bei dieser Implementierung wird mit einem zusätzlichen (virtuellen) Batterie-Wechselrichter gearbeitet. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In Vorbereitung werden die beiden anzugebenden Readings &#039;&#039;&amp;lt;pvIn&amp;gt;&#039;&#039; und &#039;&#039;&amp;lt;pvOut&amp;gt;&#039;&#039; zum Beispiel als userReadings erstellt, wobei &#039;&amp;lt;pvIn&amp;gt;&#039;&#039; und &#039;&#039;&amp;lt;pvOut&amp;gt;&#039;&#039; natürlich durch Readingnamen ersetzt werden müssen. Diese beiden Readings werden wie folgt berechnet / erstellt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;pvOut&amp;gt; = Inverter_Common_PAC_Value - PowerFlow_Site_P_Akku&lt;br /&gt;
&amp;lt;pvIn&amp;gt; = Inverter_Common_IDC_Value * Inverter_Common_UDC_Value + Inverter_Common_IDC_2_Value * Inverter_Common_UDC_2_Value&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;&#039;PV-Wechselrichter&#039;&#039;&#039; wird mit dem Attribut setupInverterDev01 definiert, wobei die angelegten Readingnamen in den Schlüsseln &#039;&#039;pvIn&#039;&#039; bzw. &#039;&#039;pvOut&#039;&#039; verwendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SymGen24 icon=inverter@#ff8c00:inverter@grey capacity=10000 strings=suedwest,nordost etotal=User_Produced_PV:kWh pvOut=&amp;lt;pvOut&amp;gt;:W pvIn=&amp;lt;pvIn&amp;gt;:W&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem PV-Wechselrichter sind die Strings &#039;&#039;suedwest&#039;&#039; und &#039;&#039;nordost&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Der zusätzliche &#039;&#039;&#039;Batterie-Wechselrichter&#039;&#039;&#039; wird mit dem Attribut setupInverterDev02 hinzugefügt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SymGen24 icon=inverter@#ff8c00:inverter@grey strings=none ac2dc=-PowerFlow_Site_P_Akku:W  dc2ac=PowerFlow_Site_P_Akku:W capacity=7680&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bemerkungen:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
- strings=none sowie die Schlüssel ac2cd und dc2ac sind typisch für einen Batterie-WR bzw. kennzeichnen einen WR als Batterie-Wechselrichter &amp;lt;br&amp;gt;&lt;br /&gt;
- die an die Batterie abgegebene Leistung ist negativ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Einbindung eines Fronius Symo GEN24 10.0 Plus mit BYD Batterie ohne (virtuellen) Batterie-Wechselrichter =====&lt;br /&gt;
Die Implementierung ist komplett auf der Seite [[Solaranlage Komplettbeispiel Fronius BYD]] beschrieben.&lt;br /&gt;
&lt;br /&gt;
Zur Integration des &#039;&#039;Fronius Symo&#039;&#039; in FHEM wird das Modul &#039;&#039;fronius.pm&#039;&#039; verwendet und in dem definierten Device &#039;&#039;Fronius_Symo_Gen24&#039;&#039; diverse userReadings erzeugt. Diese Readings werden in den korrespondierenden Schlüsseln des Attributes &#039;&#039;setupInverterDev01&#039;&#039; angegeben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setupInverterDev01 Fronius_Symo_Gen24 etotal=User_Produced_PV_Energie:kWh pvOut=PowerFlow_Site_P_PV:W capacity=6000 strings=Dach_Ost,Dach_West&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Am Wechselrichter Fronius Symo Gen24 ist eine BYD Batterie angeschlossen. Das Device &#039;&#039;PV-Batterie&#039;&#039; wird per [[ModbusAttr]] angelegt und gemanaged. Die entsprechenden Readings werden im Attribut &#039;&#039;SetupBatteryDev01&#039;&#039; hinterlegt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PV_Batterie&lt;br /&gt;
cap=10240&lt;br /&gt;
charge=BatteryChargePercent&lt;br /&gt;
icon=@dyn:@dyn:@dyn:@dyn&lt;br /&gt;
intotal=Summe_Ladung:Wh&lt;br /&gt;
outtotal=Summe_Entladung:Wh&lt;br /&gt;
pin=BatteryChargeWatt:W&lt;br /&gt;
pout=BatteryDischargeWatt:W&lt;br /&gt;
pinmax=10000&lt;br /&gt;
show=2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Einbindung eines SMA - Hybrid Sunny Tripower Smart Energy  =====&lt;br /&gt;
[[Datei:Screenshot 2025-10-05 083530.png|right|thumb|400px|SMAInverter.pm]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der genannte Wechselrichter wird über das Modul SMAInverter.pm in FHEM integriert. Die nebenstehende Abbildung zeigt und benennt die einzelnen Readings des Moduls welche in den entsprechenden Schlüsseln der SolarForecast Attribute &#039;&#039;setupInverterDevXX&#039;&#039; und &#039;&#039;setupBatteryDevXX&#039;&#039; zugeordnet werden. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Readings des SMAInverter Moduls können vor der Verwendung über geeignete Methoden (userReadings) in Readings mit sprechenden Namen überführt werden um sie mit diesen Namen in die genannten Attributschlüssel einzufügen. In der vorliegenden Lösung befinden sich die  Anwendungen SolarForecast und und die Inverter-Steuerung jeweils auf unterschiedlicher Hardware. Als Verbindungslayer wird MQTT genutzt, wobei dadurch bereits die dargestellten Readingnamen entstehen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Einbindung und Visualisierung von Umweltdaten ===&lt;br /&gt;
&lt;br /&gt;
Im Attribut &#039;&#039;&#039;setupEnvironment&#039;&#039;&#039; werden &#039;&#039;Schlüssel=Wert&#039;&#039; Paare definiert, die zur Erfassung von Umwelt- und Umfeldfaktoren dienen, die im Kontext des Moduleinsatzes und Prognosen wichtig oder hilfreich sind.&lt;br /&gt;
&lt;br /&gt;
;gridStatus: Eine &amp;lt;Gerät&amp;gt;:&amp;lt;Reading&amp;gt;:&amp;lt;Regex&amp;gt; Kombination für den Verbindungsstatus zum öffentlichen Netz. Der angegebene reguläre Ausdruck muß Boolean &#039;true&#039; für den Status &#039;Netz verfügbar/verbunden&#039; ergeben, sonst &#039;false&#039;.&lt;br /&gt;
	&lt;br /&gt;
;outsideTemp: Eine &amp;lt;Gerät&amp;gt;:&amp;lt;Reading&amp;gt; Kombination, die die aktuell gemessene Außentemperatur in °C liefert.&lt;br /&gt;
	&lt;br /&gt;
;presence: Eine &amp;lt;Gerät&amp;gt;:&amp;lt;Reading&amp;gt;:&amp;lt;Regex&amp;gt; Kombination, die den Anwesenheitsstatus der Bewohner liefert. Der angegebene reguläre Ausdruck muß Boolean &#039;true&#039; für den Status &#039;Anwesenheit&#039; ergeben, sonst &#039;false&#039;.&lt;br /&gt;
	&lt;br /&gt;
;windSpeed: Eine &amp;lt;Gerät&amp;gt;:&amp;lt;Reading&amp;gt; Kombination, die die aktuell gemessene Windgeschwindigkeit in m/s liefert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit dem Attribut und Schlüssel &#039;&#039;&#039;graphicControl-&amp;gt;headerShowEnv&#039;&#039;&#039; können diese Daten im Grafikkopf visualisiert werden. Bestimmte Umweltdaten sind die Prognosefunktionen relevant und werden bei Bedarf aufbereitet und gespeichert. Siehe dazu auch den Abschnitt [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Integration_von_Umwelt-_und_Kontextfaktoren_in_die_Prognose|&amp;quot;Integration von Umwelt- und Kontextfaktoren in die Prognose&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Erkennung Netzausfall (öffentliches Netz)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Mit der Einbindung einer geeigneten &amp;lt;Device&amp;gt;:&amp;lt;Reading&amp;gt; Kombination im Schlüssel &#039;&#039;gridStatus&#039;&#039; erfasst SolarForecast die Verbindung zum öffentlichen Stromnetz. Der Verbindungsstatus des Netzes kann im Grafikkopf mit &#039;&#039;&#039;graphicControl-&amp;gt;headerShowEnv=gridStatus&#039;&#039;&#039; neben weiteren Informationen visualisiert werden. Die Erfassung des aktuellen Netzverbindungsstatus ist eine reine Information für den Anwender.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Der integrierte SolarForecast Grafikbereich ==&lt;br /&gt;
Das SolarForecast Modul beinhaltet eine Grafikdarstellung die sich in mehrere Bereiche gliedert. Diese Bereiche können über Attribute ein- bzw. ausgeblendet sowie die Inhalte festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2024-09-21 223545.png|right|thumb|400px|Bereiche der integrierten Grafik]]&lt;br /&gt;
&lt;br /&gt;
Der nebenstehende Screenshot gibt die Gliederung der Grafikbereiche wieder:&lt;br /&gt;
&lt;br /&gt;
 1 - der Kopfbereich (Graphic Header)&lt;br /&gt;
 2 - durch den Nutzer selbst definierbarer Inhalt (Graphic Header Own Specification) als Teil des Kopfbereiches&lt;br /&gt;
 3 - Bereich Verbraucherdarstellung (Consumer Legend)&lt;br /&gt;
 4 - Bereich Balkengrafik (Beam Graphic)&lt;br /&gt;
 5 - Energieflußgrafik (Flow Graphic)&lt;br /&gt;
&lt;br /&gt;
Jeder dieser Bereiche hat spezifische Steuerungsattribute zur Anpassung des Verhaltens und ggf. des Inhalts.&lt;br /&gt;
&lt;br /&gt;
=== 1 - Der Grafik Kopfbereich ===&lt;br /&gt;
Im Kopfbereich befinden sich fest verankerte Informationen zur verwendeten Vorhersage-API sowie deren Status, Informationen zum Sonnenaufgang und Sonnenuntergang, dem aktuellen Gesamtstatus des SolarForecast Devices, Abweichungskennzahlen der PV Vorhersage sowie weitere Kennzeichen zur Verfügung.&lt;br /&gt;
Über zwei Drucktasten kann eine Anlagenprüfung durchgeführt und in den Spportthread des Moduls im FHEM Forum abgesprungen werden.&lt;br /&gt;
&lt;br /&gt;
Mit dem Attribut &#039;&#039;&#039;graphicHeaderShow&#039;&#039;&#039; kann der gesamte Kopfbereich 1 und 2 (nutzereigener Teilbereich) ausgeblendet werden. Wird der Kopfbereich ausgeblendet, ist es hilfreich mit dem Attribut &#039;&#039;&#039;plantControl-&amp;gt;showLink&#039;&#039;&#039; einen Link zur Detailgrafik einzufügen da der in der Kopfgrafik integrierte Link in diesem Fall nicht mehr zur Verfügung steht. &lt;br /&gt;
&lt;br /&gt;
Das Attribut &#039;&#039;&#039;graphicHeaderDetail&#039;&#039;&#039; definiert welche Bereiche des Grafikkopfes angezeigt werden sollen. Es kann die Anzeige des Energieverbrauches, der PV-Erzeugung und der vom Nutzer selbst definierte Inhalt miteinander frei kombiniert werden.&lt;br /&gt;
&lt;br /&gt;
=== 2 - Der Bereich mit selbst definierbarem Inhalt (Graphic Header Own Specification) ===&lt;br /&gt;
In diesem Bereich kann der User beliebige Readings, Set-Kommandos und Attribute des SolarForecast Devices oder anderer Devices, die sich im gleichen FHEM-System wie das SolarForecast Device befinden, anzeigen lassen.&lt;br /&gt;
&lt;br /&gt;
Dieser Bereich ist als Tabelle mit einer beliebigen Anzahl von Zeilen organisiert. Jede Zeile beinhaltet ein Kommentarfeld und vier Nutzfelder zur Darstellung ausgewähler Werte + Label. Der Bereich bzw. der Inhalt des Bereiches wird mit dem Attribut &#039;&#039;&#039;graphicHeaderOwnspec&#039;&#039;&#039; definiert.  &lt;br /&gt;
&lt;br /&gt;
Das nachfolgende Beispiel zeigt ein real gesetztes graphicHeaderOwnspec Attribut. Die Leerzeilen sind nicht notwendig, erhöhen aber die Lesbarkeit der Struktur.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
Autarkierate:Current_AutarkyRate&lt;br /&gt;
PV&amp;amp;nbsp;übermorgen:special_dayAfterTomorrowPVforecast&lt;br /&gt;
Verbrauch&amp;amp;nbsp;bis&amp;lt;br&amp;gt;Sunset:special_todayConForecastTillSunset&lt;br /&gt;
Verbrauch&amp;amp;nbsp;bis&amp;lt;br&amp;gt;nächsten&amp;amp;nbsp;Sunrise:special_conForecastTillNextSunrise&lt;br /&gt;
&lt;br /&gt;
#Batterie&lt;br /&gt;
BatteryLive&amp;amp;nbsp;Status:userFn_BatLive_State&lt;br /&gt;
SoC&amp;amp;nbsp;Limit:Settings_CGwacs_BatteryLife_MinimumSocLimit_value@MQTT2_cerboGX_c0619ab34e08_settings&lt;br /&gt;
SoC&amp;amp;nbsp;Ist:SOC_value@MQTT2_cerboGX_c0619ab34e08_battery&lt;br /&gt;
SOC&amp;amp;nbsp;Optimum:Battery_OptimumTargetSoC&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
aktuelle&amp;amp;nbsp;Ladung:userFn_Bat_EnergyState&lt;br /&gt;
Verfügbar:userFn_BatLive_UsableEnergy&lt;br /&gt;
benötigte&amp;amp;nbsp;Ladeenergie:userFn_Bat_EnergyRemain&lt;br /&gt;
Ladefreigabe:Battery_ChargeRecommended&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
akt.&amp;amp;nbsp;DC&amp;amp;nbsp;Strom:DC_Current_value@MQTT2_cerboGX_c0619ab34e08_battery&lt;br /&gt;
Restladezeit&amp;amp;nbsp;Ziel:userFn_Bat_HoursUntilChargeFinish&lt;br /&gt;
MPII&amp;amp;nbsp;Ladestrom&amp;lt;br&amp;gt;Limit&amp;amp;nbsp;Soll:userFn_Bat_MaxChargeCurrent_set&lt;br /&gt;
:&lt;br /&gt;
&lt;br /&gt;
#Settings&lt;br /&gt;
Batterie&amp;amp;nbsp;Lademanagement:userFn_BatteryChargeManagement&lt;br /&gt;
SoC&amp;amp;nbsp;Management:userFn_BatterySoCManagement&lt;br /&gt;
MPII&amp;amp;nbsp;Ladestrom&amp;lt;br&amp;gt;Limit&amp;amp;nbsp;Ist:MaxChargeCurrent@MQTT2_cerboGX_c0619ab34e08_vebus&lt;br /&gt;
SmartSolar&amp;lt;br&amp;gt;Einspeisung:OvervoltageFeedIn@MQTT2_cerboGX_c0619ab34e08_settings&lt;br /&gt;
&lt;br /&gt;
MPII&amp;amp;nbsp;Limit&amp;lt;br&amp;gt;Einspeisung&amp;amp;nbsp;(W):MaxFeedInPower@MQTT2_cerboGX_c0619ab34e08_settings&lt;br /&gt;
SOC&amp;amp;nbsp;Limit&amp;amp;nbsp;Soll:MinimumSocLimit@MQTT2_cerboGX_c0619ab34e08_settings&lt;br /&gt;
Verbr.&amp;amp;nbsp;Neuplanung:consumerNewPlanning&lt;br /&gt;
Wetteranzeige:graphicShowWeather &lt;br /&gt;
&lt;br /&gt;
Anzeige&amp;amp;nbsp;Nachtstunden:graphicShowNight&lt;br /&gt;
hist.&amp;amp;nbsp;Stunden:graphicHistoryHour&lt;br /&gt;
Autokorrektur:pvCorrectionFactor_Auto&lt;br /&gt;
Victron&amp;amp;nbsp;BatteryLife&amp;lt;br&amp;gt;(1=an,10=aus):BatteryLife@MQTT2_cerboGX_c0619ab34e08_settings&lt;br /&gt;
&lt;br /&gt;
Grid&amp;amp;nbsp;Setpoint:GridSetpoint@MQTT2_cerboGX_c0619ab34e08_settings&lt;br /&gt;
Debug:ctrlDebu&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommentarfeld am Beginn einer Zeile wird durch ein &#039;&#039;&#039;#&#039;&#039;&#039; gekennzeichnet. Folgt dem # ein String, wird dieser String als Kommentarangabe gewertet und in der Grafik ausgegeben. Ein leeres Kommentarfeld wird lediglich durch ein # gefolgt von einem Leerzeichen oder NL beschrieben:&lt;br /&gt;
&lt;br /&gt;
 #:&amp;lt;Text&amp;gt;  (bzw nur # für einen &#039;leeren&#039; Titel)&lt;br /&gt;
&lt;br /&gt;
Ein Netzfeld bzw. ein Datensatz wird durch die Angabe von einem Label und dem darzustellenden Wert getrennt durch &#039;:&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Label&amp;gt;:&amp;lt;Reading, Attribut oder Set-Kommando&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das System erkennt selbständig, ob es sich bei der Angabe um ein Reading, Attribut oder ein Set-Kommando handelt. Sollen Readings, Set-Kommandos und Attribute anderer Devices als dem SolarForecast-Device angezeigt werden, kann dies einfach durch Zusatz von&lt;br /&gt;
&lt;br /&gt;
 ....@&amp;lt;Device-Name&amp;gt;&lt;br /&gt;
&lt;br /&gt;
an den Parameter erreicht werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2024-12-05 203916.png|right|thumb|400px|Darstellung eigener Grafikbereich]]&lt;br /&gt;
Die Eingabe kann mehrzeilig erfolgen. Werte mit den Einheiten &amp;quot;Wh&amp;quot; bzw. &amp;quot;kWh&amp;quot; werden entsprechend der Einstellung des Attributs &#039;&#039;&#039;graphicEnergyUnit&#039;&#039;&#039; umgerechnet. Im Label sind Leerzeichen durch &amp;quot;&amp;amp;amp;nbsp;&amp;quot; einzufügen, ein Zeilenumbruch durch &amp;quot;&amp;amp;lt;br&amp;amp;gt;&amp;quot;. Ein leeres Feld in einer Zeile wird durch &amp;quot;:&amp;quot; ohne eine weitere Angabe erzeugt.&lt;br /&gt;
&lt;br /&gt;
Die nebenstehende Abbildung zeigt die reale Darstellung der oben angegebenen Struktur im Attribut graphicHeaderOwnspec.&lt;br /&gt;
&lt;br /&gt;
==== Formatierung der Inhalte im Bereich &amp;quot;Graphic Header Own Specification&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Die angezeigten Inhalte, wie z.B. Readingwerte, des User eigenen Bereiches (Attribut graphicHeaderOwnspec) können durch Spezifikationen im Attribut &#039;&#039;&#039;graphicHeaderOwnspecValForm&#039;&#039;&#039; manipuliert werden.&lt;br /&gt;
&lt;br /&gt;
Die Online-Hilfe zum Attribut graphicHeaderOwnspecValForm erläutert die verfügbaren Möglichkeiten und Optionen.&lt;br /&gt;
Als Beispiel hier einige mögliche Notationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &#039;userFn_Bat_HoursUntilChargeFinish&#039;                        =&amp;gt; &amp;quot;($VALUE).&#039; Stunden&#039;&amp;quot;,&lt;br /&gt;
  &#039;MQTT2_cerboGX_c0619ab34e08_battery.SOC_value&#039;             =&amp;gt; &amp;quot;%.1f %%&amp;quot;,&lt;br /&gt;
  &#039;Settings_CGwacs_BatteryLife_MinimumSocLimit_value&#039;        =&amp;gt; &amp;quot;%.1f %%&amp;quot;,&lt;br /&gt;
  &#039;Info_MaxChargeCurrent_value&#039;                              =&amp;gt; &amp;quot;($VALUE).&#039; A&#039;&amp;quot;,&lt;br /&gt;
  &#039;DC_Current_value&#039;                                         =&amp;gt; &amp;quot;%.0f A&amp;quot;,&lt;br /&gt;
  &#039;MQTT2_cerboGX_c0619ab34e08_solarcharger_Common.Regulated&#039; =&amp;gt; &amp;quot;($VALUE eq &#039;1&#039; ? &#039;Ja&#039; : &#039;Nein&#039;)&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Besonderheit besteht bei darzustellenden Werten die die Einheiten &#039;Wh&#039; bzw. &#039;kWh&#039; besitzen. Diese Werte und Einheiten werden automatisch entsprechend des gesetzten Attributes graphicEnergyUnit umgerechnet und angezeigt.&lt;br /&gt;
&lt;br /&gt;
Soll in diesen Fällen eine automatische Formatierung umgangen werden, kann eine solche Notation verwendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &#039;Today_PVforecast&#039; =&amp;gt; &amp;quot;(sprintf &#039;%.1f &amp;amp;amp;nbsp;kWh&#039;, ($VALUE / 1000))&amp;quot;,&lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/pre&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Die Angabe von &amp;amp;amp;nbsp; vor &#039;kWh&#039; verhindert die Erkennung der Einheit und so auch die automatische Umsetzung durch das Modul. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 3 - Bereich Verbraucherdarstellung (Consumer Legend) ===&lt;br /&gt;
Dieser Grafikbereich zeigt die im Modul registrierten Verbraucher sowie deren Status und weitere Informationen an. Sind die Voraussetzungen gegeben, d.h. entsprechende Schlüssel in der ConsumerXX-Attributen gesetzt, können die Verbraucher über das Paneel manuell geschaltet werden.&lt;br /&gt;
&lt;br /&gt;
Zur Anpassung der Darstellung sind verschiedene Attribute verfügbar:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;consumerControl-&amp;gt;showLegend: Definiert die Lage bzw. Darstellungsweise der Verbraucherlegende sofern Verbraucher im SolarForecast Device registriert sind.&lt;br /&gt;
;consumerControl-&amp;gt;adviceIcon: Definiert die Art der Information über die geplanten Schaltzeiten eines Verbrauchers in der Verbraucherlegende. &lt;br /&gt;
;consumerControl-&amp;gt;detailLink: Wenn gesetzt, ist der jeweilige Verbraucher klickbar um direkt zur Detailansicht des jeweiligen Geräts auf einer neuen Browserseite zu gelangen. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Im Standard wird das Verbraucherpaneel zwischen dem Kopfbereich und der ersten Balkengrafik Ebene dargestellt. Mit dem Attribut &#039;&#039;&#039;consumerControl-&amp;gt;showLegend&#039;&#039;&#039; und Argument &#039;&#039;&#039;icon_bottom&#039;&#039;&#039; oder &#039;&#039;&#039;text_bottom&#039;&#039;&#039; kann das Verbraucherpaneel an das Ende des Grafikbereiches verschoben werden.&lt;br /&gt;
Die Verwendung von &#039;&#039;&#039;text_bottom&#039;&#039;&#039; oder &#039;&#039;&#039;text_top&#039;&#039;&#039; blendet die Icon-Spalte im Verbraucherpaneel aus.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Screenshot 2025-02-08 093239.png|Darstellung mit consumerControl showLegend=icon_top (default)&lt;br /&gt;
File:Screenshot 2025-02-08 093646.png|Darstellung mit consumerControl showLegend=icon_bottom&lt;br /&gt;
File:Screenshot 2025-02-08 152018.png|Darstellung mit consumerControl showLegend=text_top bzw. text_bottom&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2025-02-08 213634.png|right|thumb|400px|]]&lt;br /&gt;
Ein Mouse-Over über das Uhrensymbol zeigt nähere Informationen zum Status, den Planungsdaten, Modus und weitere Daten des Verbrauchers. Der Schalter &amp;quot;Aus/Ein&amp;quot; visualisiert den Schaltzustand des Verbrauchers und können auch zum manuellen Schalten des Verbrauchers dienen. Voraussetzung ist, dass im consumer-Attribut die Schlüssel &amp;quot;on&amp;quot; und &amp;quot;off&amp;quot; mit den Set-Kommandos zum Schalten des Verbrauchers defininiert sind.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2025-02-08 222210.png|right|thumb|300px|]]&lt;br /&gt;
Der Auto-Schieberegler zeigt einerseits den Freigabestatus zum Schalten des Verbrauchers durch das SolarForecast Modul und kann andererseits manuell betätigt werden. Der Status des Reglers korrespondiert mit dem im zugehörigen Consumer Attribut vorhandenen Schlüssel &#039;&#039;&#039;auto&#039;&#039;&#039; angegebenen Reading-Wert.&lt;br /&gt;
&lt;br /&gt;
Die Verbraucherbezeichnungen in dem Paneel können in der Standardkonfiguration angeklickt werden um direkt zur Detailansicht des Devices zu gelangen. Mit dem Attribut &#039;&#039;&#039;consumerControl-&amp;gt;detailLink&#039;&#039;&#039; kann der Link zur Detailansicht deaktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Das Uhrensymbol kann mit dem Attribut &#039;&#039;&#039;consumerControl-&amp;gt;adviceIcon&#039;&#039;&#039; geändert und/oder dessen Farbe angepasst, sowie einen Informationstext statt eines Icons angezeigt werden. &lt;br /&gt;
&lt;br /&gt;
=== 4 - Bereich Balkengrafik (Beam Graphic) ===&lt;br /&gt;
&lt;br /&gt;
Die Balkengrafik des Moduls ist ein wesentliches Visualisierungshilfsmittel. Im Auslieferungszustand existiert eine Balkengrafikebene, die &#039;&#039;&#039;Ebene 1&#039;&#039;&#039;.&lt;br /&gt;
Jede Ebene kann zwei Balkendiagramme mit auswählbaren Inhalten, Farben und einstellbarem LayoutTyp darstellen. In Ebene 1 kann die Wettervorhersage eingebettet oder, bei Vorhandensein von Batteriegeräten, die zukünftigen Zeiten mit empfohlener Ladefreigabe und SoC-Prognose eingeblendet werden. &lt;br /&gt;
&lt;br /&gt;
Welche Daten in welchen Zeiträumen dargestellt werden sollen, die Bestimmung des Layouts, die Gestaltung der Balken und einiges mehr wird durch Attribute gesteuert. Ein Teil dieser Einstellungen wird über das zusammengesetzete Attribut &#039;&#039;&#039;graphicControl-&amp;gt;&#039;Schlüssel&#039;=&#039;Wert&#039;&#039;&#039;&#039; eingestellt:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::*&#039;&#039;&#039;grundsätzliche Layout Definitionen&#039;&#039;&#039;&lt;br /&gt;
[[Datei:Screenshot 2025-01-12 204342.png|right|thumb|400px|Standardanzeige mit Wetter-Icons, gesetzen Attributen graphicBeam1Color=D4C177, graphicHistoryHour=11]]&lt;br /&gt;
&lt;br /&gt;
;graphicControl-&amp;gt;beamHeightlevel:Faktor zur Berechnung der Höhenverhältnisse der jeweiligen Ebene (siehe auch diesen [[#Wirkung_von_graphicControl-&amp;gt;beamHeightlevel_auf_die_Zonen_(z1_bis_z3)_je_nach_layoutType|Abschnitt]]). &lt;br /&gt;
;graphicControl-&amp;gt;beamPaddingTop:Legt den Platz in px im Balkendiagramm fest, der zwischen dem oberen Rand der jeweiligen Balkengrafik Ebene und der ersten Text- oder Iconreihe dieser Ebene eingefügt wird.&lt;br /&gt;
;graphicControl-&amp;gt;beamPaddingBottom:Legt den Platz in px im Balkendiagramm fest, der zwischen der letzten Text- oder Iconreihe der jeweiligen Balkengrafik Ebene und dem unteren Rand dieser Ebene eingefügt wird. &lt;br /&gt;
;graphicControl-&amp;gt;layoutType:Layout-Optionen zur grundlegenden Gestaltung der Balkengrafik&lt;br /&gt;
;graphicControl-&amp;gt;hourStyle:Format der Zeitangabe in der Balkengrafik&lt;br /&gt;
;graphicControl-&amp;gt;hourCount:Anzahl der darzustellenden Balken/Stunden in der Balkengrafk&lt;br /&gt;
[[Datei:Screenshot Screenshot 2025-05-21 153613.png|right|thumb|400px|Erweiterung des oberen und unteren Abstandes mit den Attributen graphicControl-&amp;gt;beamPaddingTop und graphicControl-&amp;gt;beamPaddingBottom]]&lt;br /&gt;
;graphicControl-&amp;gt;energyUnit:definiert die Einheit zur Anzeige der elektrischen Leistung in der Grafik&lt;br /&gt;
;graphicHistoryHour:Anzahl der vorangegangenen Stunden die in der Balkengrafik dargestellt werden&lt;br /&gt;
;graphicControl-&amp;gt;beamWidth:Vorgabe Breite der Balken der Balkengrafik in px (sonst automatische Bestimmung)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::*&#039;&#039;&#039;Definition der Inhalte und Balkeneigenschaften&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2025-01-12 204756.png|right|thumb|400px|Wie oben aber mit gesetzem Attribut graphicShowNight=1]]&lt;br /&gt;
;graphicBeam1Color:Farbauswahl des primären Balkens (Ebene 1)&lt;br /&gt;
;graphicBeam2Color:Farbauswahl des sekundären Balkens (Ebene 1)&lt;br /&gt;
;graphicBeam1Content:Legt den darzustellenden Inhalt des primären Balken fest (Ebene 1)&lt;br /&gt;
;graphicBeam2Content:Legt den darzustellenden Inhalt des sekundären Balken fest (Ebene 1)&lt;br /&gt;
;graphicBeam1FontColor:Auswahl der Schriftfarbe des primären Balkens (Ebene 1)&lt;br /&gt;
;graphicBeam2FontColor:Auswahl der Schriftfarbe des sekundären Balkens (Ebene 1)&lt;br /&gt;
[[Datei:Screenshot 2025-01-12 205024.png|right|thumb|400px|Balkengrafik mit aktivierter Ebene 2, gesetzem Attribut graphicShowNight=0 (ohne Zeitsynchronisation zwischen Ebene 1 und Ebene 2)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::*&#039;&#039;&#039;zusätzliche Optionen&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
;graphicShowNight:Anzeigen oder Verbergen der Nachtstunden in der Balkengrafik&lt;br /&gt;
;graphicShowWeather:Wettericons in der Balkengrafik anzeigen/verbergen (nur Ebene 1)&lt;br /&gt;
;graphicWeatherColor:Farbe der Wetter-Icons für die Tagesstunden&lt;br /&gt;
;graphicWeatherColorNight:Farbe der Wetter-Icons für die Nachtstunden&lt;br /&gt;
;graphicShowDiff:Zusätzliche Anzeige der Differenz &amp;quot;&amp;lt;primärer Balkeninhalt&amp;gt; - &amp;lt;sekundärer Balkeninhalt&amp;gt;&amp;quot; im Kopf- oder Fußbereich der Balkengrafik&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die genaue Beschreibung und deren Optionen sind der aktuellen Online-Hilfe zu entnehmen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für alle Ebenen gilt:&#039;&#039;&#039; Ein Attribut mit einer ungeraden Balkennummer (z.B. graphicBeam1Content) bezieht sich immer auf den primären Balken, ein Attribut mit einer geraden Balkennummer (z.B. graphicBeam2Content) bezieht sich immer auf den sekundären Balken.&lt;br /&gt;
&lt;br /&gt;
Die Balken haben, wie die meisten Elemente in der Balkengrafik, eine Mouse-Over Eigenschaft welche relevante Informationen zu den dargestellten Werten anzeigt. &lt;br /&gt;
&lt;br /&gt;
Sind die Nachtstunden mit &#039;&#039;&#039;graphicShowNight&#039;&#039;&#039; ausgeblendet, werden keine Balken angezeigt sofern es keine Werte anzuzeigen gibt. Sollten dennoch Werte ungleich 0 anzuzeigen sein, werden diese Werte auch trotz ausgeblendeter Nachstunden angezeigt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Aktivierung der Balkengrafik Ebene 2 ====&lt;br /&gt;
[[Datei:Screenshot 2025-01-12 211741.png|right|thumb|400px|Balkengrafik mit aktivierter Ebene 2, gesetzem Attribut graphicShowNight=01 (mit Zeitsynchronisation zwischen Ebene 1 und Ebene 2)]]&lt;br /&gt;
&lt;br /&gt;
Um die &#039;&#039;&#039;Ebene 2&#039;&#039;&#039; der Balkengrafik zu aktivieren, setzt man das Attribut &#039;&#039;&#039;graphicBeam3Content&#039;&#039;&#039; und/oder &#039;&#039;&#039;graphicBeam4Content&#039;&#039;&#039; mit den gewünschten darzustellenden Inhalten. Die weiteren Darstellungsoptionen, wie graphicBeamCColor, können ebenfalls für den jeweiligen Balken selektiv definiert werden wenn ein Attribut mit der entsprechenden Nummer (z.B. 4 für Balken 4) vorhanden ist. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Die Wetter-Icons können nur in Ebene 1 integriert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Werden in der Balkengrafik die Nachtstunden ausgeblendet (&#039;&#039;&#039;graphicShowNight=0&#039;&#039;&#039; bzw. default), findet zwischen der Ebene 1 und der Ebene 2 keine Synchronisation der Zeitebene statt. Falls es einen inhaltlichen Zusammenhang zwischen den Werten der Ebene 1 und Ebene 2 gibt, eine Zeitsynchronisation zwischen den Ebenen wünschenswert und sinnvoll. Durch Setzen des Attrbut &#039;&#039;&#039;graphicShowNight=01&#039;&#039;&#039; kann diese Synchronisation eingeschaltet werden. &lt;br /&gt;
&lt;br /&gt;
Dabei ist die Ebene 1 die führende Ebene, d.h. diese Ebene vererbt die exkludierten bzw. eventuell inkludierten Nachtstunden (wenn Werte in den Balken der Ebene 1 angezeigt werden sollen) an die nachfolgende Ebene.&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
==== Aktivierung der Balkengrafik Ebene 3 ====&lt;br /&gt;
&lt;br /&gt;
Um die &#039;&#039;&#039;Ebene 3&#039;&#039;&#039; der Balkengrafik zu aktivieren, setzt man das Attribut &#039;&#039;&#039;graphicBeam5Content&#039;&#039;&#039; und/oder &#039;&#039;&#039;graphicBeam6Content&#039;&#039;&#039; mit den gewünschten darzustellenden Inhalten. Die weiteren Darstellungsoptionen, wie graphicBeamCColor, können ebenfalls für den jeweiligen Balken selektiv definiert werden wenn ein Attribut mit der entsprechenden Nummer (z.B. 5 für Balken 5) vorhanden ist. &lt;br /&gt;
&lt;br /&gt;
Werden in der Balkengrafik die Nachtstunden ausgeblendet (&#039;&#039;&#039;graphicShowNight=0&#039;&#039;&#039; bzw. default), findet zwischen der Ebene 1 und der Ebene 3 keine Synchronisation der Zeitebene statt. Falls es einen inhaltlichen Zusammenhang zwischen den Werten der Ebene 1 und Ebene 3 gibt, ist eine Zeitsynchronisation zwischen den Ebenen wünschenswert und sinnvoll. Durch Setzen des Attrbut &#039;&#039;&#039;graphicShowNight=01&#039;&#039;&#039; kann diese Synchronisation eingeschaltet werden. &lt;br /&gt;
&lt;br /&gt;
Dabei ist die Ebene 1 die führende Ebene, d.h. diese Ebene vererbt die exkludierten bzw. eventuell inkludierten Nachtstunden (wenn Werte in den Balken der Ebene 1 angezeigt werden sollen) an die nachfolgenden Ebenen, d.h. auch auf die Ebene 3.&lt;br /&gt;
&lt;br /&gt;
  &lt;br /&gt;
==== Wirkung von graphicControl-&amp;gt;beamHeightlevel auf die Zonen (z1 bis z3) je nach layoutType ====&lt;br /&gt;
&lt;br /&gt;
🎯 &#039;&#039;&#039;Grundprinzip&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jede der verfügbaren Ebenen ist in Zonen aufgeteilt. Die Wirkung und der Einsatz der Zonen ist vom verwendeten &#039;&#039;graphicControl-&amp;gt;layoutType&#039;&#039; abhängig. &amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;graphicControl-&amp;gt;beamHeightlevel&#039;&#039; ist ein &#039;&#039;&#039;Skalierungsfaktor&#039;&#039;&#039;, der verwendet wird um für jede Zone die &#039;&#039;&#039;resultierende Zonenhöhe (px)&#039;&#039;&#039; zu berechnen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
𝑝𝑥 = 𝑔𝑟𝑜𝑢𝑛𝑑 + (𝑣𝑎𝑙 / 𝑚𝑎𝑥𝑉𝑎𝑙) ⋅ (𝑏𝑒𝑎𝑚𝐻𝑒𝑖𝑔ℎ𝑡𝑙𝑒𝑣𝑒𝑙 − 𝑔𝑟𝑜𝑢𝑛𝑑)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das bedeutet:&lt;br /&gt;
* beamHeightlevel bestimmt die &#039;&#039;&#039;maximale mögliche Höhe&#039;&#039;&#039;, die ein Balken erreichen kann,&lt;br /&gt;
* aber die tatsächliche Höhe hängt &#039;&#039;&#039;immer&#039;&#039;&#039; vom Verhältnis val / maxVal und vom scaleMode ab.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🧩 &#039;&#039;&#039;Zonenmodell (z1–z3)&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unabhängig vom layoutType besteht jede Balkenebene (z.Zt. Ebene 1 bis 3) aus Zonen, die übereinander angeordnet sind:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Zone !! Bedeutung !! Sichtbare Wirkung&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;z1&#039;&#039;&#039; || Freiraum über dem Balken (Abstand, Zahlen, Icons) || Abstand nach oben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;z2&#039;&#039;&#039; || Balken mit dem höchsten positiven Wert oder oberer Teil eines Stapels || sichtbarer höherer (primärer) Balken&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;z3&#039;&#039;&#039; || Balken mit dem niedrigeren positiven Wert double/staple oder negativer Bereich (diff) || kleinerer (sekundärer) Balken oder negativer Balken&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Summe aus z1 + z2 + z3 ergibt die &#039;&#039;&#039;Gesamthöhe&#039;&#039;&#039;, die durch &#039;&#039;beamHeightlevel&#039;&#039; &#039;&#039;&#039;skaliert&#039;&#039;&#039;, aber nicht fest vorgegeben wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🧩 &#039;&#039;&#039;Wirkung pro layoutType&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Datei:Zonenskizze.png|right|thumb|400px|Zonenskizze]]&lt;br /&gt;
🟦 &#039;&#039;&#039;layoutType = single&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zonen:&lt;br /&gt;
* z1 = Freiraum&lt;br /&gt;
* z2 = Balken (beam1)&lt;br /&gt;
* z3 = nicht genutzt&lt;br /&gt;
&lt;br /&gt;
Wirkung von &#039;&#039;beamHeightlevel&#039;&#039;:&lt;br /&gt;
* skaliert die Gesamthöhe von z1 + z2&lt;br /&gt;
* z2 wächst proportional zu &#039;&#039;val / maxVal&#039;&#039;&lt;br /&gt;
* z1 ist der verbleibende Rest&lt;br /&gt;
* kleine Werte können bei linearer Skalierung sehr klein werden&lt;br /&gt;
* &#039;&#039;scaleMode=log&#039;&#039; macht kleine Werte sichtbar größer&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🟩 &#039;&#039;&#039;layoutType = double&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zonen:&lt;br /&gt;
* z1 = Freiraum&lt;br /&gt;
* z2 = größerer Wert (beam1 oder beam2)&lt;br /&gt;
* z3 = kleinerer Wert oder Stapelanteil&lt;br /&gt;
&lt;br /&gt;
Wirkung von &#039;&#039;beamHeightlevel&#039;&#039;:&lt;br /&gt;
* skaliert die Gesamthöhe des Balkenpaares&lt;br /&gt;
* z2 und z3 teilen sich die Höhe proportional&lt;br /&gt;
* bei großen Wertunterschieden wird z3 sehr dünn&lt;br /&gt;
* bei &#039;&#039;scaleMode=staple&#039;&#039; werden beide Werte übereinander gestapelt&lt;br /&gt;
* bei &#039;&#039;scaleMode=log&#039;&#039; werden Unterschiede geglättet&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🟥 &#039;&#039;&#039;layoutType = diff&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zonen:&lt;br /&gt;
* z1 = positiver Freiraum&lt;br /&gt;
* z2 = positiver Balken (falls diff &amp;gt; 0)&lt;br /&gt;
* z3 = negativer Balken (falls diff &amp;lt; 0) &amp;lt;br&amp;gt;Hinweis: technisch existiert auch z4 als Freiraum unterhalb, aber visuell Teil von z3&lt;br /&gt;
&lt;br /&gt;
Wirkung von &#039;&#039;beamHeightlevel&#039;&#039;:&lt;br /&gt;
* skaliert die Gesamthöhe der diff‑Darstellung&lt;br /&gt;
* die Null-Linie wird &#039;&#039;&#039;dynamisch verschoben&#039;&#039;&#039;, abhängig von maxDif/minDif&lt;br /&gt;
* dadurch ändern sich die relativen Höhen von z1/z2/z3&lt;br /&gt;
* große Ausreißer verschieben die Null-Linie stark&lt;br /&gt;
* kleine Werte können optisch verschwinden&lt;br /&gt;
* &#039;&#039;scaleMode=log&#039;&#039; kann die Darstellung stabilisieren&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
⚙️ &#039;&#039;&#039;Einfluss des scaleMode&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! scaleMode !! Wirkung auf die Zonen&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;lin&#039;&#039;&#039; || z2/z3 werden proportional zu den Rohwerten skaliert → große Unterschiede sichtbar&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;log&#039;&#039;&#039; || z2/z3 werden logarithmisch gedämpft → kleine Werte werden sichtbarer&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;staple&#039;&#039;&#039; || nur für layoutType=double: z2 und z3 werden übereinander gestapelt&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;beamHeightlevel&#039;&#039; wirkt in allen Modi als &#039;&#039;&#039;Multiplikator&#039;&#039;&#039;, der die resultierenden Höhen streckt oder staucht.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 5 - Die Energieflußgrafik (Flow Graphic) ===&lt;br /&gt;
[[Datei:Screenshot 2025-02-13 213424.png|right|thumb|400px|Energieflußgrafik mit Verbrauchern in der Nachtdarstellung (Mondphasen) nach Sonnenuntergang]]&lt;br /&gt;
&lt;br /&gt;
Die Energieflußgrafik stellt die registrierten Erzeuger, Batterien, Netzzugänge und Verbraucher strukturiert in mehreren Ebenen dar:&lt;br /&gt;
&lt;br /&gt;
;Ebene 1: In der oberen Ebene befinden sich die PV-Generatoren, Smart-Loader sowie sonstigen Erzeuger &lt;br /&gt;
;Ebene 2: Die mittlere Ebene organisiert den Zugang zum öffentlichen Netz, dem Hausknoten, dem Batterieknoten sowie einem Dummy-Verbraucher (Lampensymbol) für den Energieverbrauch des Hauses der keinem der registrierten Verbraucher zugeordnet werden kann.&lt;br /&gt;
;Ebene 3: In der unteren Ebene werden die registrierten Verbraucher dargestellt. Unterhalb der Verbrauchersymbole werden der aktuelle Verbrauch (bzw. der On/Off-Zustand) sowie darunter die Restlaufzeit (Minuten) des Verbrauchers, sofern er durch das Modul geplant und gestartet wurde. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Position und Gestaltung der Grafikelemente ist umfangreich über das Attribut &#039;&#039;&#039;flowGraphicControl&#039;&#039;&#039; und den darin verfügbaren Schlüsseln einstellbar.&lt;br /&gt;
Die Bedeutung der Schlüssel ist in der Online-Hilfe zum Attribut mit einem Beispiel beschrieben. &lt;br /&gt;
&lt;br /&gt;
Darüber hinaus enthalten die Setup-Attribute &#039;&#039;&#039;setupInverterDevXX&#039;&#039;&#039;, &#039;&#039;&#039;setupOtherProducerXX&#039;&#039;&#039; und &#039;&#039;&#039;consumerXX&#039;&#039;&#039; weitere Einstellungsmöglichkeiten um deren Icons und Färbungen in der Flußgrafik individuell einstellen zu können. So sind zum Beispiel die Icons der PV-Inverter und deren Färbung mit dem Schlüssel &#039;&#039;&#039;icon&#039;&#039;&#039; der setupInverterDevXX-Attribute in Abhängigkeit von Tag und Nacht separat definierbar.&lt;br /&gt;
&lt;br /&gt;
In den Verbraucher-Attributen ist mit dem Schlüssel &#039;&#039;&#039;noshow&#039;&#039;&#039; die Sichtbarkeit in der Flußgrafik definierbar.&lt;br /&gt;
&lt;br /&gt;
Generell steuert das Attribut &#039;&#039;&#039;graphicSelect&#039;&#039;&#039; die Ein- bzw. Ausblendung der gesamten Flußgrafik.&lt;br /&gt;
&lt;br /&gt;
== Bestimmung von Sonnenaufgang und Sonnenuntergang ==&lt;br /&gt;
&lt;br /&gt;
Im Modul werden die Zeiten für den Sonnenaufgang und Sonnenuntergang aus alternativen Quellen verwendet. Es gelten dabei die folgenden Prioritäten.&lt;br /&gt;
&lt;br /&gt;
* sind die lokalen Koordinaten &#039;&#039;latitude, longitude, altitude&#039;&#039; im &#039;&#039;global&#039;&#039; Device gesetzt, erfolgt die Berechnung dieser Daten mit dem Parameter &#039;&#039;&#039;HORIZON=-0.833&#039;&#039;&#039; (vgl. CommandRef zu [https://fhem.de/commandref_DE.html#SUNRISE_EL SUNRISE_EL]). &lt;br /&gt;
&lt;br /&gt;
* sollten die lokalen Koordinaten nicht gesetzt sein, werden die Angaben aus dem in Attribut &#039;&#039;setupWeatherDev1&#039;&#039; angegebenen Wetter-Device entnommen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der Wert &#039;&#039;−0.833°&#039;&#039; entspricht dem international üblichen Standard für die Berechnung von Sonnenauf‑ und untergangszeiten. Er berücksichtigt sowohl die atmosphärische Refraktion als auch den halben Sonnendurchmesser und beschreibt damit den Moment, in dem der obere Sonnenrand scheinbar den Horizont berührt. Viele astronomische Algorithmen und [https://metacpan.org/release/JFORGET/DateTime-Event-Sunrise-0.0505/view/lib/DateTime/Event/Sunrise.pm Bibliotheken] verwenden diesen Wert als Default, weshalb er auch in SolarForecast eingesetzt wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Die Verbrauchsprognose ==&lt;br /&gt;
Im Gegensatz zu der PV Prognose gibt es keine API oder andere externen Datenquellen die für die Verbrauchsprognose herangezogen werden könnten.&lt;br /&gt;
&lt;br /&gt;
Zum Zweck der Verbrauchsermittlung verwendet das Modul die Meterdaten aus dem Attribut &#039;&#039;setupMeterDev&#039;&#039; sowie den weiteren setup-Attributen &#039;&#039;setupInverterDevXX&#039;&#039;. &lt;br /&gt;
Sind auch andere Erzeuger (BHKW, Windanlagen, etc.) bzw. eine Batterie vorhanden, sind ebenfalls die Attribute &#039;&#039;setupOtherProducerXX&#039;&#039; bzw. &#039;&#039;setupBatteryDev&#039;&#039; für die Berechnung des Hausverbrauchs relevant. In diesen Attributen gibt es die Schlüssel &#039;&#039;*total&#039;&#039; die teilweise optional sind. Für die Verbrauchsprognose bilden sie jedoch die Berechnungsgrundlage und sind deswegen für diese Funktionalität wichtig anzugeben.&lt;br /&gt;
&lt;br /&gt;
Die Verbrauchswerte werden stundengenau erfasst und im Datenspeicher &#039;&#039;pvHistory&#039;&#039; für 31 Tage, sowie im Datenspeicher &#039;&#039;pvCircular&#039;&#039; 210 Tage gespeichert. Die beiden Datenspeicher übernehmen unterschiedliche Aufgaben im Rahmen der Prognoseerstellung. Auf Grundlage der gespeicherten und somit historischen Verbrauchswerte erstellt das Modul eine Prognose für die kommende Zeit.&lt;br /&gt;
&lt;br /&gt;
Mit dem Kommando  &lt;br /&gt;
&lt;br /&gt;
    &amp;quot;get ... pvHistory [Tag]&amp;quot; &lt;br /&gt;
&lt;br /&gt;
wird der Inhalt aufgelistet. Die Schlüssel &#039;&#039;confc&#039;&#039;, &#039;&#039;con&#039;&#039; und &#039;&#039;gcon&#039;&#039; zeigen die Verbrauchsprognose, den Verbrauch und den Netzbezug der jeweiligen Stunde des gewählten Tages.&lt;br /&gt;
Die Stunde &amp;quot;99&amp;quot; zeigt die Summen dieser Schlüsssel für den Tag:&lt;br /&gt;
&lt;br /&gt;
      99 =&amp;gt; etotal: , pvfc: 782, pvrl: 0, rad1h: -&lt;br /&gt;
            confc: 14540, con: 13873, gcon: 13873, gfeedin: 0&lt;br /&gt;
            batintotal: , batin: 0, batouttotal: , batout: 0&lt;br /&gt;
            batmaxsoc: -, batsetsoc: -&lt;br /&gt;
            wid: , wcc: , wrp: , pvcorrf: , dayname: So&lt;br /&gt;
            cyclescsm01: 0&lt;br /&gt;
            cyclescsm02: 0&lt;br /&gt;
            cyclescsm03: 0&lt;br /&gt;
            cyclescsm04: 1, hourscsme04: 0.00&lt;br /&gt;
            cyclescsm05: 0&lt;br /&gt;
            cyclescsm06: 0&lt;br /&gt;
            cyclescsm07: 1, hourscsme07: 0.00&lt;br /&gt;
            cyclescsm08: 1, hourscsme08: 0.00&lt;br /&gt;
            cyclescsm09: 1, hourscsme09: 0.03 &lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wurden für den Tag 14540 Wh Verbrauch prognostiziert, 13873 Wh tatsächlich verbraucht und davon 13873 Wh aus dem Netz bezogen. Leider war an diesem Tag keinerlei PV Ertrag vorhanden, was man auch an dem Schlüssel &#039;&#039;pvrl&#039;&#039; erkennen kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Den Inhalt des pvCircular-Speichers kann mit dem Befehl  &lt;br /&gt;
&lt;br /&gt;
     &amp;quot;get ... pvCircular [Tag]&amp;quot;&lt;br /&gt;
&lt;br /&gt;
angezeigt werden. Das nachfolgende Beispiel zeigt die Ausgabe für die Tagesstunde 23:&lt;br /&gt;
&lt;br /&gt;
 23 =&amp;gt; pvapifc: 0, pvaifc: -, pvfc: 0, aihit: 0, pvrl: 0&lt;br /&gt;
       batin01: 0, batin02: -, batin03: -&lt;br /&gt;
       batout01: 619, batout02: -, batout03: -&lt;br /&gt;
       confc: 650, gcon: 23, gfeedin: 0, wcc: 40, rr1c: 0.00&lt;br /&gt;
       temp: -6.00, wid: 100, wtxt: Bewölkungsentwicklung nicht beobachtet&lt;br /&gt;
       pprl01: -, pprl02: -, pprl03: -&lt;br /&gt;
       ... &lt;br /&gt;
       con_all =&amp;gt; Sa  @ 617 762&lt;br /&gt;
                  Di  @ 693 645&lt;br /&gt;
                  Mo  @ 620 679&lt;br /&gt;
                  So  @ 669 666 636&lt;br /&gt;
                  Mi  @ 701 626&lt;br /&gt;
                  Do  @ 612 642&lt;br /&gt;
                  Fr  @ 615 606&lt;br /&gt;
&lt;br /&gt;
Der Schüssel &#039;&#039;con_all&#039;&#039; enthält einen Hash aus Arrays die für jeden Wochentag (Mo..So) bis zu 30 Verbrauchswerte (in Wh) für die angezeigte Stunde speichern. Wie hier erkennbar ist, wurden an den drei vergangenen Sonntagen jweils 669 Wh, 666 Wh bzw. 636 Wh in der Stunde 23 (22:00-22:59) verbraucht.&lt;br /&gt;
Der Median aus diesen Werten geht in die Verbrauchsprognose ein. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Die Wochentagsnamen Mo..So sind von den installierten Locales auf Betriebsystemebene abhängig. Ist keine deutsche locale installiert, werden die englischen Wochentagsnamen Mon..Sun verwendet.    &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausblick (ab V 2.0.0, aktuell in Entwicklung):&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Die Verbrauchsprognose kann zukünftig auf &#039;&#039;&#039;herkömmliche Weise (Legacy)&#039;&#039;&#039; erstellt oder &#039;&#039;&#039;durch eine KI&#039;&#039;&#039; erstellt werden. Es ist auch eine prozentual einstellbare Kombination aus beiden Ergebnissen möglich. Weiter unten werden beide Varianten beschrieben. Bitte beachten, dass beide Technologien ihre spezifischen Attribute zur Einstellung haben.&lt;br /&gt;
&lt;br /&gt;
Die KI-gestützte Prognose verwendet Langzeitdaten, die sich in einem speziellen Datenspeicher befinden und mit&lt;br /&gt;
&lt;br /&gt;
 get &amp;lt;Name&amp;gt; valDecTree aiRawData&lt;br /&gt;
&lt;br /&gt;
eingesehen werden können. Wie lange diese Daten aufbewahrt werden, ist mit dem Attribut&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; aiControl-&amp;gt;aiStorageDuration&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
einstellbar. Eine Pflege dieser Daten ist mit dem Befehl&lt;br /&gt;
&lt;br /&gt;
 set &amp;lt;Name&amp;gt; reset aiData ...&lt;br /&gt;
&lt;br /&gt;
möglich.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Wie wird der Verbrauch des Hauses ermittelt und gespeichert? ===&lt;br /&gt;
&lt;br /&gt;
Die Verbrauchsdaten des Hauses werden auf Stundenbasis ermittelt und gespeichert. Das &amp;quot;Haus&amp;quot; steht als Synonym aller im Kontext des Solarforecast Devices zusammengeführten Inverter (setupInverterDevXX), sonstigen Erzeuger (setupOtherProducerXX), Netzanschlüsse (setupMeterDev), Verbraucher (consumerXX) und Batterien (setupBatteryDev).&lt;br /&gt;
&lt;br /&gt;
Alle diese Daten werden durch das Modul mit jedem ausgeführten Zyklus (Attribut plantControl-&amp;gt;cycleInterval) und ebenfalls bei auftreten von Events eines als &#039;asynchron&#039; definierten Devices gesammelt. Daraus wird permanent ein aktualisierter Verbrauch berechnet. Die Berechnung beschreibt folgende Formel: &lt;br /&gt;
&lt;br /&gt;
 PV-Erzeugung + sonstige Erzeugung - Netzeinspeisung + Netzbezug - Batterieladung + Batterieentladung - Verbrauch = 0&lt;br /&gt;
&lt;br /&gt;
bzw.&lt;br /&gt;
 &lt;br /&gt;
 Verbrauch (Wh) = PV-Erzeugung + sonstige Erzeugung - Netzeinspeisung + Netzbezug - Batterieladung + Batterieentladung&lt;br /&gt;
            con = PV           + PP                 - GridIn          + GridCon   - BatIn          + BatOut&lt;br /&gt;
&lt;br /&gt;
Die PV-Erzeugung beinhaltet die Summe aller durch die angegebnen Inverter (setupInverterDev01 .. setupInverterDevXX) erzeugten Energien. Die &amp;quot;sonstige Erzeugung&amp;quot; summiert sich aus den Werten aller angegebenen Producer (setupOtherProducer01 .. setupOtherProducerXX). Der Verbrauch wird durch die registrierten Geräte consumerXX teilweise direkt erfasst, ist aber grundsätzlich unvollständig da nicht alle Verbrauchswerte im &amp;quot;Haus&amp;quot; gemessen und durch das Modul erfasst werden können.&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt das Ergebnis bei 300 Wh PV-Erzeugung und gleichzeitige 500 Wh Netzbezug:&lt;br /&gt;
&lt;br /&gt;
 Verbrauch = 300 + 0 - 0 + 500 - 0 + 0 = 800 Wh&lt;br /&gt;
&lt;br /&gt;
Bei 1300Wh PV-Erzeugung, 100 Wh Netzeinspeisung sowie 200 Wh Batterieladung ergibt sich der Verbrauch zu:&lt;br /&gt;
&lt;br /&gt;
 Verbrauch = 1300 + 0 - 100 + 0 - 200 + 0 = 1000 Wh&lt;br /&gt;
&lt;br /&gt;
Ohne Erzeugung, aber mit der Energielieferung von 500 Wh aus der Batterie, 800 Wh Netzbezug (mit einem Anteil Batterienachladung aus dem Netz von 200 Wh) sieht die Verbrauchsrechnung wie folgt aus: &lt;br /&gt;
&lt;br /&gt;
 Verbrauch = 0 + 0 - 0 + 800 - 200 + 500 = 1100 Wh&lt;br /&gt;
&lt;br /&gt;
Der so ermittelte Verbrauchsert wird mit jedem Zyklus in der pvHistory im Schlüssel &amp;quot;con&amp;quot; gespeichert. Man kann sich die gespeicherten Werte mit dem Befehl&lt;br /&gt;
&lt;br /&gt;
 get &amp;lt;name&amp;gt; pvHistory [&amp;lt;Tag&amp;gt;]&lt;br /&gt;
&lt;br /&gt;
angezeigt werden. Nachfolgendes Beispiel zeigt einen Datensatz für die Stunde 8 eines Tages:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      08 =&amp;gt; pvfc: 0, pvrl: 0, pvrlvd: 1, rad1h: -&lt;br /&gt;
            etotali01: 62940734, etotali02: 2928860, etotali03: -&lt;br /&gt;
            pvrl01: 0, pvrl02: 0, pvrl03: -&lt;br /&gt;
            etotalp01: -, etotalp02: -, etotalp03: -&lt;br /&gt;
            pprl01: -, pprl02: -, pprl03: -&lt;br /&gt;
            confc: 630, con: 962, gcons: 962, conprice: 0.2958&lt;br /&gt;
            gfeedin: 0, feedprice: 0.1269&lt;br /&gt;
            DoN: 0, sunaz: 120, sunalt: -3&lt;br /&gt;
            batintotal: 3713815.07742543, batouttotal: 3604468.26993988, batin: 0, batout: 0&lt;br /&gt;
            wid: 161, wcc: 89, rr1c: 0.00, pvcorrf: 0.27/0.00 temp: 7.40, &lt;br /&gt;
            csmt01: 110996.12, csme01: 32.1399999999994, minutescsm01: 30&lt;br /&gt;
            minutescsm02: 0&lt;br /&gt;
            csmt03: 2513.67, csme03: 0, minutescsm03: 0&lt;br /&gt;
            csmt04: 1581293.6, csme04: 136.5, minutescsm04: 60&lt;br /&gt;
            csmt05: 1662.17, csme05: 0, minutescsm05: 0&lt;br /&gt;
            csmt06: 90.53, csme06: 0, minutescsm06: 0&lt;br /&gt;
            csmt07: 39.75, csme07: 0, minutescsm07: 0&lt;br /&gt;
            csmt08: 38050, csme08: 0, minutescsm08: 0&lt;br /&gt;
            csmt09: 131627, csme09: 33.2000000000116, minutescsm09: 39&lt;br /&gt;
            minutescsm10: 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Schlüssel &amp;quot;con&amp;quot; ist der gespeicherte Verbrauch von 962 Wh ersichtlich.&lt;br /&gt;
&lt;br /&gt;
Zur Laufzeit bekommt man mit dem Attribut &#039;&#039;ctrlDebug=collectData&#039;&#039; einen Einblick in die Verbrauchsermittlung bei jedem Zyklus und kann so die Eingangswerte und das daraus resultierende Ergebnis im FHEM Log nachverfolgen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
2024.11.28 11:38:20.080 1: SolCast DEBUG&amp;gt; EnergyConsumption input -&amp;gt; PV: 96, PP: 0, GridIn: 0, GridCon: 582, BatIn: 5, BatOut: 0&lt;br /&gt;
2024.11.28 11:38:20.081 1: SolCast DEBUG&amp;gt; EnergyConsumption result -&amp;gt; 673 Wh&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Die Legacy-Verbrauchsprognose einstellen ===&lt;br /&gt;
==== Wie wird die Legacy-Verbrauchsprognose erstellt? ====&lt;br /&gt;
&lt;br /&gt;
Aus den gespeicherten con-Werten (Verbrauchsdaten) der pvCircular (Schlüssel con_all) sowie Einträgen der pvHistory wird der Median der historischen Tage ermittelt und für den kommenden Tag bzw. die kommen Stunden zur Prognose angewendet. Dabei geht per default jeder verfügbare historische Tag gleichberechtigt in die Prognose ein. Mit dem Attribut &#039;&#039;&#039;plantControl-&amp;gt;consForecastIdentWeekdays=1&#039;&#039;&#039; kann festgelegt werden, dass nur gleiche Wochentage (Mo..So) für die Prognose verwendet werden. Hierbei spielt die Vermutung, dass das Verbrauchsverhalten eine gewisse Korrelation zum Wochentag hat, eine Rolle. &lt;br /&gt;
&lt;br /&gt;
Verwendet man die Einstellung consForecastIdentWeekdays=1, hat es sich als vorteilhaft erwiesen, das Attribut &#039;&#039;&#039;plantControl-&amp;gt;consForecastLastDays&#039;&#039;&#039; auf einen niedrigeren Wert als den Default zu setzen. Eine Einstellung auf &#039;8&#039; zum Beispiel verwendet den Median der gleichen Wochentage der vergangenenen 8 Wochen. Dadurch wird nicht zu weit in die Vergangenheit verzweigt und so eine langsame Veränderung des Verbrauchsmedian, zum Beispiel hervorgerufen durch den Übergang vom Winter in das Frühjahr hinein, abgebildet.&lt;br /&gt;
&lt;br /&gt;
Weiteren Einfluß auf die Verbrauchsprognose kann mit dem Schlüssel &#039;&#039;&#039;exconfc&#039;&#039;&#039; im Consumerattribut genommen werden. Insbesondere bei der unregelmäßigen Nutzung von Verbrauchern mit hoher Leistung kann die Projektion der aufgezeichneten historischen Werte in die Prognose zu unverhältnismäßig hohen Verbrauchswerwartunden führen. &lt;br /&gt;
&lt;br /&gt;
Möglicherweise führt in Fällen die Verwendung eine der nachfolgenden Optionen zu einem besseren Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;1 -&#039;&#039;&#039; die allgemeine Verbrauchsprognose wird um die gespeicherten Energieverbrauchsanteile reduziert.&lt;br /&gt;
* &#039;&#039;&#039;2 -&#039;&#039;&#039; wie bei &#039;1&#039;, jedoch gehen die Planungsdaten des Verbrauchers bei der Prognose der kommenden Stunden wieder mit ein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird &#039;&#039;&#039;exconfc&#039;&#039;&#039; in einem der Consumer verwendet, sollte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;plantControl-&amp;gt;consForecastIdentWeekdays=1&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;plantControl-&amp;gt;consForecastLastDays=4&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
eingestellt werden. Hintergrund ist, dass die Verbrauchsanteile der jeweiligen Verbraucher nur maximal 31 Tage in der pvHistory verfügbar sind. Für längere Zeiträume stehen nur Gesamtsummen des Verbrauchs in der pvCircular zu Verfügung.  &lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;&#039;exconfc=1&#039;&#039;&#039; werden die in der Historie aufgezeichneten Verbrauchsbestandteile aus einer Prognose herausgerechnet. Konkret werden die in der pvHistory aufgezeichneten Verbrauchsbestandteile für die relevante Stunde ermittelt und daraus ein Durchschnitt gebildet der vom Prognosewert subtrahiert wird. Mit dem Attributwert plantControl-&amp;gt;consForecastIdentWeekdays=1 werden wiederum nur identische Wochentage (Mo .. So) zusammengefasst.&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;&#039;exconfc=2&#039;&#039;&#039; erfolgt ebenso die Eliminierung des Verbrauchsanteils, es wird jedoch auf die Planungsdaten für diesen Verbraucher zugegriffen und die geplanten Energieanteile wiederum der Verbrauchsprognose für die kommenden Stunden hinzugerechnet.&lt;br /&gt;
&lt;br /&gt;
In beiden Anwendungsfällen ist es notwendig, dass dem Modul durch die Angabe entsprechender Readings der Energieverbrauch im Setup des Consumers bekannt gemacht wird damit diese Energieanteile registriert werden können. Allgemein funktioniert die Verbrauchsprognose gut wenn Verbrauchsprozesse regelmäßig in einem wiederkehrenden Zeitraster ablaufen, der Verbrauch durch persönliche Rituale bestimmt ist. So zum Beispiel könnte am Dienstag und Samstag gewöhnlich die Waschmaschine laufen, das E-Auto täglich aufgeladen werden und gebügelt wird oft am Sonntag Nachmittag.&lt;br /&gt;
&lt;br /&gt;
Unregelmäßige Nutzung, vor allem vom Großverbrauchern, lässt sich nur sehr schwer und ungenügend auf zukünftige Verbrauchsprognosen projizieren.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis der Prognose wird im Kopf der Grafik in der Zeile &#039;&#039;Verbrauch&#039;&#039; sowie in diversen Readings wie &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RestOfDayConsumptionForecast&#039;&#039;&#039; (Verbrauchsprognose für den Rest des Tages)&lt;br /&gt;
* &#039;&#039;&#039;NextHours_Sum04_ConsumptionForecast&#039;&#039;&#039; (Verbrauchsprognose für die nächsten 4 Stunden)&lt;br /&gt;
* &#039;&#039;&#039;Tomorrow_ConsumptionForecast&#039;&#039;&#039; (Verbrauchsprognose für den kommenden Tag)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
angezeigt.&lt;br /&gt;
&lt;br /&gt;
Weitere Aggregationen kann man sich über das Attribut &#039;&#039;&#039;ctrlStatisticReadings&#039;&#039;&#039; bei Bedarf zuschalten:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;conForecastTillNextSunrise&#039;&#039;&#039; - Verbrauchsprognose von aktueller Stunde bis zum kommenden Sonnenaufgang&lt;br /&gt;
* &#039;&#039;&#039;todayConForecastTillSunset&#039;&#039;&#039; - Verbrauchsprognose von aktueller Stunde bis Stunde vor Sonnenuntergang&lt;br /&gt;
* &#039;&#039;&#039;todayConsumptionForecast&#039;&#039;&#039; - Verbrauchsprognose aufgesplittet pro Stunde des aktuellen Tages (01-24) &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Debugging der Legacy-Verbrauchsprognose ====&lt;br /&gt;
&lt;br /&gt;
Um sich einen Einblick über die Erstellung der Verbrauchsprognose zu verschaffen, bietet sich die Einschaltung von:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; ctrlDebug consumption_long&lt;br /&gt;
&lt;br /&gt;
an. Mit diesem gesetzten Attribut wird die Erstellung der Prognose im Log protokolliert:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
2025.02.27 19:52:00.063 1: SolCast DEBUG&amp;gt; ################### Start Consumption forecast ###################&lt;br /&gt;
2025.02.27 19:52:00.063 1: SolCast DEBUG&amp;gt; Basics - installed locale: de_DE.UTF-8, used scheme: DE&lt;br /&gt;
2025.02.27 19:52:00.064 1: SolCast DEBUG&amp;gt; process Today dayname: Do, Tomorrow dayname: Fr&lt;br /&gt;
2025.02.27 19:52:00.065 1: SolCast DEBUG&amp;gt; consumer &#039;03&#039; register for exclude day 13, hod: 01 - 74.43 Wh&lt;br /&gt;
2025.02.27 19:52:00.065 1: SolCast DEBUG&amp;gt; consumer &#039;03&#039; register for exclude day 13, hod: 10 - 290.77 Wh&lt;br /&gt;
2025.02.27 19:52:00.065 1: SolCast DEBUG&amp;gt; consumer &#039;03&#039; register for exclude day 13, hod: 24 - 660.70 Wh&lt;br /&gt;
2025.02.27 19:52:00.066 1: SolCast DEBUG&amp;gt; consumer &#039;03&#039; register for exclude day 20, hod: 07 - 459.93 Wh&lt;br /&gt;
2025.02.27 19:52:00.066 1: SolCast DEBUG&amp;gt; consumer &#039;07&#039; register for exclude day 20, hod: 02 - 0.33 Wh&lt;br /&gt;
2025.02.27 19:52:00.067 1: SolCast DEBUG&amp;gt; consumer &#039;03&#039; register for exclude day 30, hod: 08 - 264.78 Wh&lt;br /&gt;
2025.02.27 19:52:00.067 1: SolCast DEBUG&amp;gt; ################### Consumption forecast for the next Hours (new median) ###################&lt;br /&gt;
2025.02.27 19:52:00.067 1: SolCast DEBUG&amp;gt; excl. hist 74 Wh for Hour 01, Considered value numbers: 1&lt;br /&gt;
2025.02.27 19:52:00.067 1: SolCast DEBUG&amp;gt; estimated cons of Hour 01: 436 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.068 1: SolCast DEBUG&amp;gt; excl. hist 0 Wh for Hour 02, Considered value numbers: 1&lt;br /&gt;
2025.02.27 19:52:00.068 1: SolCast DEBUG&amp;gt; estimated cons of Hour 02: 428 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.068 1: SolCast DEBUG&amp;gt; estimated cons of Hour 03: 458 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.068 1: SolCast DEBUG&amp;gt; estimated cons of Hour 04: 503 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.069 1: SolCast DEBUG&amp;gt; estimated cons of Hour 05: 489 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.069 1: SolCast DEBUG&amp;gt; estimated cons of Hour 06: 482 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.069 1: SolCast DEBUG&amp;gt; excl. hist 460 Wh for Hour 07, Considered value numbers: 1&lt;br /&gt;
2025.02.27 19:52:00.069 1: SolCast DEBUG&amp;gt; estimated cons of Hour 07: 274 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.070 1: SolCast DEBUG&amp;gt; excl. hist 265 Wh for Hour 08, Considered value numbers: 1&lt;br /&gt;
2025.02.27 19:52:00.070 1: SolCast DEBUG&amp;gt; estimated cons of Hour 08: 441 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.070 1: SolCast DEBUG&amp;gt; estimated cons of Hour 09: 558 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.070 1: SolCast DEBUG&amp;gt; excl. hist 291 Wh for Hour 10, Considered value numbers: 1&lt;br /&gt;
2025.02.27 19:52:00.071 1: SolCast DEBUG&amp;gt; estimated cons of Hour 10: 443 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.071 1: SolCast DEBUG&amp;gt; estimated cons of Hour 11: 881 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.071 1: SolCast DEBUG&amp;gt; estimated cons of Hour 12: 794 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.072 1: SolCast DEBUG&amp;gt; estimated cons of Hour 13: 840 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.072 1: SolCast DEBUG&amp;gt; estimated cons of Hour 14: 660 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.072 1: SolCast DEBUG&amp;gt; estimated cons of Hour 15: 812 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.072 1: SolCast DEBUG&amp;gt; estimated cons of Hour 16: 752 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.073 1: SolCast DEBUG&amp;gt; estimated cons of Hour 17: 597 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.073 1: SolCast DEBUG&amp;gt; estimated cons of Hour 18: 652 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.073 1: SolCast DEBUG&amp;gt; estimated cons of Hour 19: 634 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.073 1: SolCast DEBUG&amp;gt; estimated cons of Hour 20: 628 Wh, Considered value numbers: 3&lt;br /&gt;
2025.02.27 19:52:00.074 1: SolCast DEBUG&amp;gt; estimated cons of Hour 21: 713 Wh, Considered value numbers: 3&lt;br /&gt;
2025.02.27 19:52:00.074 1: SolCast DEBUG&amp;gt; estimated cons of Hour 22: 596 Wh, Considered value numbers: 3&lt;br /&gt;
2025.02.27 19:52:00.074 1: SolCast DEBUG&amp;gt; estimated cons of Hour 23: 629 Wh, Considered value numbers: 3&lt;br /&gt;
2025.02.27 19:52:00.074 1: SolCast DEBUG&amp;gt; excl. hist 661 Wh for Hour 24, Considered value numbers: 1&lt;br /&gt;
2025.02.27 19:52:00.075 1: SolCast DEBUG&amp;gt; estimated cons of Hour 24: 660 Wh, Considered value numbers: 3&lt;br /&gt;
2025.02.27 19:52:00.075 1: SolCast DEBUG&amp;gt; ################### Consumption forecast for the next day (new median) ###################&lt;br /&gt;
2025.02.27 19:52:00.075 1: SolCast DEBUG&amp;gt; estimated cons Tomorrow: 16848 Wh, Individual hourly values considered: 72, exclude: 0 Wh (avg of 0 entities)&lt;br /&gt;
2025.02.27 19:52:00.075 1: SolCast DEBUG&amp;gt; ################### Store Consumption forecast values (new median) ###################&lt;br /&gt;
2025.02.27 19:52:00.076 1: SolCast DEBUG&amp;gt; store &#039;NextHour00&#039; hod &#039;20&#039; confc: 628, confcEx: 628&lt;br /&gt;
2025.02.27 19:52:00.076 1: SolCast DEBUG&amp;gt; store circular/history hod &#039;20&#039; confc: 628&lt;br /&gt;
2025.02.27 19:52:00.076 1: SolCast DEBUG&amp;gt; store &#039;NextHour01&#039; hod &#039;21&#039; confc: 713, confcEx: 713&lt;br /&gt;
2025.02.27 19:52:00.077 1: SolCast DEBUG&amp;gt; store circular/history hod &#039;21&#039; confc: 713&lt;br /&gt;
2025.02.27 19:52:00.077 1: SolCast DEBUG&amp;gt; store &#039;NextHour02&#039; hod &#039;22&#039; confc: 596, confcEx: 596&lt;br /&gt;
2025.02.27 19:52:00.077 1: SolCast DEBUG&amp;gt; store circular/history hod &#039;22&#039; confc: 596&lt;br /&gt;
2025.02.27 19:52:00.077 1: SolCast DEBUG&amp;gt; store &#039;NextHour03&#039; hod &#039;23&#039; confc: 629, confcEx: 629&lt;br /&gt;
2025.02.27 19:52:00.078 1: SolCast DEBUG&amp;gt; store circular/history hod &#039;23&#039; confc: 629&lt;br /&gt;
2025.02.27 19:52:00.078 1: SolCast DEBUG&amp;gt; store &#039;NextHour04&#039; hod &#039;24&#039; confc: 660, confcEx: 660&lt;br /&gt;
2025.02.27 19:52:00.078 1: SolCast DEBUG&amp;gt; store circular/history hod &#039;24&#039; confc: 660&lt;br /&gt;
2025.02.27 19:52:00.079 1: SolCast DEBUG&amp;gt; store &#039;NextHour05&#039; hod &#039;01&#039; confc: 436, confcEx: 436&lt;br /&gt;
2025.02.27 19:52:00.079 1: SolCast DEBUG&amp;gt; store &#039;NextHour06&#039; hod &#039;02&#039; confc: 428, confcEx: 428&lt;br /&gt;
2025.02.27 19:52:00.079 1: SolCast DEBUG&amp;gt; store &#039;NextHour07&#039; hod &#039;03&#039; confc: 458, confcEx: 458&lt;br /&gt;
2025.02.27 19:52:00.079 1: SolCast DEBUG&amp;gt; store &#039;NextHour08&#039; hod &#039;04&#039; confc: 503, confcEx: 503&lt;br /&gt;
2025.02.27 19:52:00.080 1: SolCast DEBUG&amp;gt; store &#039;NextHour09&#039; hod &#039;05&#039; confc: 489, confcEx: 489&lt;br /&gt;
2025.02.27 19:52:00.080 1: SolCast DEBUG&amp;gt; store &#039;NextHour10&#039; hod &#039;06&#039; confc: 482, confcEx: 482&lt;br /&gt;
2025.02.27 19:52:00.080 1: SolCast DEBUG&amp;gt; store &#039;NextHour11&#039; hod &#039;07&#039; confc: 274, confcEx: 274&lt;br /&gt;
2025.02.27 19:52:00.081 1: SolCast DEBUG&amp;gt; store &#039;NextHour12&#039; hod &#039;08&#039; confc: 441, confcEx: 441&lt;br /&gt;
2025.02.27 19:52:00.081 1: SolCast DEBUG&amp;gt; store &#039;NextHour13&#039; hod &#039;09&#039; confc: 558, confcEx: 558&lt;br /&gt;
2025.02.27 19:52:00.081 1: SolCast DEBUG&amp;gt; store &#039;NextHour14&#039; hod &#039;10&#039; confc: 443, confcEx: 443&lt;br /&gt;
2025.02.27 19:52:00.081 1: SolCast DEBUG&amp;gt; store &#039;NextHour15&#039; hod &#039;11&#039; confc: 881, confcEx: 881&lt;br /&gt;
2025.02.27 19:52:00.082 1: SolCast DEBUG&amp;gt; store &#039;NextHour16&#039; hod &#039;12&#039; confc: 794, confcEx: 794&lt;br /&gt;
2025.02.27 19:52:00.082 1: SolCast DEBUG&amp;gt; store &#039;NextHour17&#039; hod &#039;13&#039; confc: 840, confcEx: 840&lt;br /&gt;
2025.02.27 19:52:00.082 1: SolCast DEBUG&amp;gt; store &#039;NextHour18&#039; hod &#039;14&#039; confc: 660, confcEx: 660&lt;br /&gt;
2025.02.27 19:52:00.083 1: SolCast DEBUG&amp;gt; store &#039;NextHour19&#039; hod &#039;15&#039; confc: 812, confcEx: 812&lt;br /&gt;
2025.02.27 19:52:00.083 1: SolCast DEBUG&amp;gt; store &#039;NextHour20&#039; hod &#039;16&#039; confc: 752, confcEx: 752&lt;br /&gt;
2025.02.27 19:52:00.083 1: SolCast DEBUG&amp;gt; store &#039;NextHour21&#039; hod &#039;17&#039; confc: 597, confcEx: 597&lt;br /&gt;
2025.02.27 19:52:00.083 1: SolCast DEBUG&amp;gt; store &#039;NextHour22&#039; hod &#039;18&#039; confc: 652, confcEx: 652&lt;br /&gt;
2025.02.27 19:52:00.084 1: SolCast DEBUG&amp;gt; store &#039;NextHour23&#039; hod &#039;19&#039; confc: 634, confcEx: 634&lt;br /&gt;
2025.02.27 19:52:00.084 1: SolCast DEBUG&amp;gt; store &#039;NextHour24&#039; hod &#039;20&#039; confc: 628, confcEx: 628&lt;br /&gt;
2025.02.27 19:52:00.084 1: SolCast DEBUG&amp;gt; store &#039;NextHour25&#039; hod &#039;21&#039; confc: 713, confcEx: 713&lt;br /&gt;
2025.02.27 19:52:00.084 1: SolCast DEBUG&amp;gt; store &#039;NextHour26&#039; hod &#039;22&#039; confc: 596, confcEx: 596&lt;br /&gt;
2025.02.27 19:52:00.085 1: SolCast DEBUG&amp;gt; store &#039;NextHour27&#039; hod &#039;23&#039; confc: 629, confcEx: 629&lt;br /&gt;
2025.02.27 19:52:00.085 1: SolCast DEBUG&amp;gt; store &#039;NextHour28&#039; hod &#039;24&#039; confc: 660, confcEx: 660&lt;br /&gt;
2025.02.27 19:52:00.086 1: SolCast DEBUG&amp;gt; consumption calculated - day: 27, hod: 20, con: 574 Wh&lt;br /&gt;
2025.02.27 19:52:00.086 1: SolCast DEBUG&amp;gt; write pvCircular consumption - hod: 99, todayConsumption: 11210 Wh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Ausgabe startet mit &#039;&#039;&amp;quot;Start Consumption forecast&#039;&#039;&amp;quot;, es werden die zu exkludierenden historischen Daten für jeden Consumer bzgl. jedem Tag (day) und Stunde des Tages (hod) getrennt registriert. Diese Werte werden durch die gespeicherte Einträge in der pvHistory (max. 31 historische Tage) geliefert. &lt;br /&gt;
&lt;br /&gt;
Im nächsten Abschnitt &#039;&#039;&amp;quot;Consumption forecast for the next Hours (new median)&amp;quot;&#039;&#039; werden die Prognosen für die nächsten Stunden kalkuliert und die zuvor registrierten Excludes angewendet. Die Prognose für den kommenden Tag ist im Abschnitt &#039;&#039;&amp;quot;Consumption forecast for the next day (new median)&amp;quot;&#039;&#039; protokolliert. Die Prognose für den kommenden Tag ist nicht einfach die Summe der Prognose der nächsten Stunden, denn in den kommenden Stunden werden auch die verfügbaren Planungen der Consumer einbezogen. Für den kommenden Tag können diese Werte unter Umständen nicht einbezogen werden da sie zum Zeitpunkt X noch nicht verfügbar sind.&lt;br /&gt;
&lt;br /&gt;
Im Abschnitt &#039;&#039;&amp;quot;Store Consumption forecast values (new median)&amp;quot;&#039;&#039; erscheinen die effektiv gespeicherten Werte. Diese sind die Grandlage für die grafische Darstellung sowie weiteren Kalkulationen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Wie kann eine fehlerhafte Legacy-Verbrauchsprognose korrigiert werden? ====&lt;br /&gt;
Wie im vorherigen Abschnitt beschrieben, wird die Prognose aus den gespeicherten &amp;quot;con&amp;quot;-Werten der vergangenen Tage (bzw. Stunden) abgeleitet. &lt;br /&gt;
Grundsätzlich muß zunächst sichergestellt werden, dass die auszulesenden Readings der angegebenen Energiezähler sowie deren Einheiten! korrekt eingestellt sind. Das gilt ebenfalls für die registrierten Verbraucher im Modul.&lt;br /&gt;
&lt;br /&gt;
Für einen ersten Überblick bietet sich das Debug Attribut an zu setzen:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; ctrlDebug consumption_long&lt;br /&gt;
&lt;br /&gt;
Beispielausgabe des Debug:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
2024.09.21 13:28:27.041 1: SolCast DEBUG&amp;gt; ################### Consumption forecast for the next day ###################&lt;br /&gt;
2024.09.21 13:28:27.042 1: SolCast DEBUG&amp;gt; History Consumption day &amp;gt;01&amp;lt; considering possible exclusions: 14082&lt;br /&gt;
2024.09.21 13:28:27.042 1: SolCast DEBUG&amp;gt; History Consumption day &amp;gt;08&amp;lt; considering possible exclusions: 16446&lt;br /&gt;
2024.09.21 13:28:27.042 1: SolCast DEBUG&amp;gt; History Consumption day &amp;gt;15&amp;lt; considering possible exclusions: 14568&lt;br /&gt;
2024.09.21 13:28:27.043 1: SolCast DEBUG&amp;gt; History Consumption day &amp;gt;25&amp;lt; considering possible exclusions: 15522&lt;br /&gt;
2024.09.21 13:28:27.043 1: SolCast DEBUG&amp;gt; estimated Consumption for tomorrow: 15154, days for avg: 4&lt;br /&gt;
2024.09.21 13:28:27.043 1: SolCast DEBUG&amp;gt; ################### Consumption forecast for the next hours ###################&lt;br /&gt;
2024.09.21 13:28:27.044 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 07, hod: 14 -&amp;gt; 850 Wh&lt;br /&gt;
2024.09.21 13:28:27.044 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 14, hod: 14 -&amp;gt; 643 Wh&lt;br /&gt;
2024.09.21 13:28:27.044 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 24, hod: 14 -&amp;gt; 590 Wh&lt;br /&gt;
2024.09.21 13:28:27.045 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 31, hod: 14 -&amp;gt; 522 Wh&lt;br /&gt;
2024.09.21 13:28:27.045 1: SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 13:00:00, confc: 651, days for avg: 4, hist. consumption registered consumers: 560.97&lt;br /&gt;
2024.09.21 13:28:27.046 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 07, hod: 15 -&amp;gt; 720 Wh&lt;br /&gt;
2024.09.21 13:28:27.046 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 14, hod: 15 -&amp;gt; 743 Wh&lt;br /&gt;
2024.09.21 13:28:27.046 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 24, hod: 15 -&amp;gt; 897 Wh&lt;br /&gt;
2024.09.21 13:28:27.047 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 31, hod: 15 -&amp;gt; 557 Wh&lt;br /&gt;
2024.09.21 13:28:27.047 1: SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 14:00:00, confc: 729, days for avg: 4, hist. consumption registered consumers: 620.97&lt;br /&gt;
2024.09.21 13:28:27.047 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 07, hod: 16 -&amp;gt; 676 Wh&lt;br /&gt;
2024.09.21 13:28:27.048 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 14, hod: 16 -&amp;gt; 790 Wh&lt;br /&gt;
2024.09.21 13:28:27.048 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 24, hod: 16 -&amp;gt; 785 Wh&lt;br /&gt;
2024.09.21 13:28:27.048 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 31, hod: 16 -&amp;gt; 581 Wh&lt;br /&gt;
2024.09.21 13:28:27.049 1: SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 15:00:00, confc: 708, days for avg: 4, hist. consumption registered consumers: 647.29&lt;br /&gt;
2024.09.21 13:28:27.049 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 07, hod: 17 -&amp;gt; 622 Wh&lt;br /&gt;
2024.09.21 13:28:27.050 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 14, hod: 17 -&amp;gt; 639 Wh&lt;br /&gt;
2024.09.21 13:28:27.050 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 24, hod: 17 -&amp;gt; 646 Wh&lt;br /&gt;
2024.09.21 13:28:27.050 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 31, hod: 17 -&amp;gt; 572 Wh&lt;br /&gt;
2024.09.21 13:28:27.051 1: SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 16:00:00, confc: 619, days for avg: 4, hist. consumption registered consumers: 618.30&lt;br /&gt;
2024.09.21 13:28:27.051 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 07, hod: 18 -&amp;gt; 596 Wh&lt;br /&gt;
2024.09.21 13:28:27.051 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 14, hod: 18 -&amp;gt; 614 Wh&lt;br /&gt;
2024.09.21 13:28:27.052 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 24, hod: 18 -&amp;gt; 580 Wh&lt;br /&gt;
2024.09.21 13:28:27.052 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 31, hod: 18 -&amp;gt; 480 Wh&lt;br /&gt;
2024.09.21 13:28:27.052 1: SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 17:00:00, confc: 567, days for avg: 4, hist. consumption registered consumers: 583.41&lt;br /&gt;
2024.09.21 13:28:27.053 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 07, hod: 19 -&amp;gt; 615 Wh&lt;br /&gt;
2024.09.21 13:28:27.053 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 14, hod: 19 -&amp;gt; 1659 Wh&lt;br /&gt;
2024.09.21 13:28:27.053 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 24, hod: 19 -&amp;gt; 597 Wh&lt;br /&gt;
2024.09.21 13:28:27.054 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 31, hod: 19 -&amp;gt; 618 Wh&lt;br /&gt;
2024.09.21 13:28:27.054 1: SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 18:00:00, confc: 872, days for avg: 4, hist. consumption registered consumers: 636.97&lt;br /&gt;
2024.09.21 13:28:27.055 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 07, hod: 20 -&amp;gt; 611 Wh&lt;br /&gt;
2024.09.21 13:28:27.055 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 14, hod: 20 -&amp;gt; 1124 Wh&lt;br /&gt;
2024.09.21 13:28:27.055 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 24, hod: 20 -&amp;gt; 546 Wh&lt;br /&gt;
2024.09.21 13:28:27.056 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 31, hod: 20 -&amp;gt; 479 Wh&lt;br /&gt;
2024.09.21 13:28:27.056 1: SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 19:00:00, confc: 690, days for avg: 4, hist. consumption registered consumers: 578.87&lt;br /&gt;
2024.09.21 13:28:27.056 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 07, hod: 21 -&amp;gt; 1474 Wh&lt;br /&gt;
2024.09.21 13:28:27.057 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 14, hod: 21 -&amp;gt; 596 Wh&lt;br /&gt;
2024.09.21 13:28:27.057 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 24, hod: 21 -&amp;gt; 619 Wh&lt;br /&gt;
2024.09.21 13:28:27.057 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 31, hod: 21 -&amp;gt; 433 Wh&lt;br /&gt;
2024.09.21 13:28:27.058 1: SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 20:00:00, confc: 780, days for avg: 4, hist. consumption registered consumers: 584.96&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Im ersten Teil wird die erwartete Consumption für den nächsten Tag unter Berücksichtigung möglicher Ausschlüsse von Verbrauchern ausgegeben. Ausschlüsse von Verbrauchern ergeben sich wenn in dem Verbraucherattribut der Schlüssel &#039;&#039;&#039;exconfc&#039;&#039;&#039; gesetzt ist. Er besagt, dass die Verbrauchswerte des Verbrauchers in eine zukünftige Prognose nicht eingehen sollen. Zum Beispiel wenn ein Verbraucher mit sehr hohen Verbrauchswerten nur sporadisch eingesetzt wird und dadurch die Prognose stark verfälschen würde. Es ist auch zu sehen, dass bedingt durch das Attribut &#039;&#039;&#039;affectConsForecastIdentWeekdays = 1&#039;&#039;&#039; nur die historischen Tage 01, 08, 15 und 25 berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Im zweiten Teil wird die berechnete Erwartung für die nächsten Stunden ausgegeben. &lt;br /&gt;
Zur Beschreibung der Fehlersuche gehen wir davon aus, dass die Prognose von 780 Wh am 2024-09-21 20:00:00 zu hoch erscheint weil am Tag &amp;quot;07&amp;quot; ein Wert von 1474 Wh gespeichert ist:&lt;br /&gt;
&lt;br /&gt;
 SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 20:00:00, confc: 780, days for avg: 4, hist. consumption registered consumers: 584.96&lt;br /&gt;
&lt;br /&gt;
Im nächsten Schritt geben wir die historischen Werte für den Tag 07 aus:&lt;br /&gt;
&lt;br /&gt;
 get &amp;lt;Name&amp;gt; pvHistory 07&lt;br /&gt;
&lt;br /&gt;
In dem Datensatz interessiert die Stunde 21. Sie resultiert aus der obigen Angabe &amp;quot;starttime: xxxx-xx-xx 20:00:00&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      21 =&amp;gt; etotal: 64354660, pvfc: 0, pvrl: 0, pvrlvd: 1, rad1h: -&lt;br /&gt;
            etotalp01: -, etotalp02: -, etotalp03: -&lt;br /&gt;
            pprl01: -, pprl02: -, pprl03: -&lt;br /&gt;
            confc: 496, con: 1474, gcons: 23, conprice: 0.2958&lt;br /&gt;
            gfeedin: 5, feedprice: 0.1269&lt;br /&gt;
            DoN: 0, sunaz: 289, sunalt: -8&lt;br /&gt;
            batintotal: 3064096.92456668, batouttotal: 2958021.37946804, batin: 0, batout: 1460&lt;br /&gt;
            wid: 101, wcc: 20, rr1c: 0.00, pvcorrf: 1.00/-temp: 26.00, &lt;br /&gt;
            csmt01: 64262.43, csme01: 28.8099999999977, minutescsm01: 25&lt;br /&gt;
            minutescsm02: 0&lt;br /&gt;
            csmt03: 0, csme03: 0, minutescsm03: 0&lt;br /&gt;
            csmt04: 1389417.4, csme04: 94.5, minutescsm04: 60&lt;br /&gt;
            csmt05: 0, csme05: 0, minutescsm05: 0&lt;br /&gt;
            csmt06: 290.15, csme06: 6.66999999999996, minutescsm06: 54&lt;br /&gt;
            csmt07: 0, csme07: 0, minutescsm07: 0&lt;br /&gt;
            csmt08: 32800, csme08: 0, minutescsm08: 0&lt;br /&gt;
            csmt09: 103987.8, csme09: 38, minutescsm09: 43&lt;br /&gt;
            csmt10: 9151.24999999783, csme10: 3.99999999997999, minutescsm10: 60&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Datensatz sind die Energieverbrauchsanteile der im Device registrierten Verbraucher mit dem Schlüssel &amp;quot;csmeXX&amp;quot; gespeichert. Dabei ist &amp;quot;XX&amp;quot; die Verbrauchernummer. In dem Beispiel existieren die Anteile csme01 und csme03 - csme10. Keiner dieser Verbraucher hat einen auffälligen Verbrauchswert gespeichert, d.h. die Messung der Verbraucher scheidet als Problemquelle aus. Wäre ein unverhältmismäßig hoher Verbrauch bei einem der Verbraucher feststellbar, müssten die Schlüssel &#039;&#039;&#039;pcurr&#039;&#039;&#039; und &#039;&#039;&#039;etotal&#039;&#039;&#039; im consumerXX-Attribut geprüft, sowie die Datenlieferung des Consumerdevices selbst geprüft werden.  &lt;br /&gt;
&lt;br /&gt;
Es wurde offensichtlich ein hoher Verbrauch von einem nicht registrierten Verbraucher verursacht oder durch die Übertragung eines Meßfehlers des Devices, angegeben im Attribut &#039;&#039;&#039;setupMeterDev&#039;&#039;&#039;, in das SolarForecast Device übertragen. Eine weitere Analyse ist an dieser Stelle nicht möglich.&lt;br /&gt;
&lt;br /&gt;
Zur Behebung des falschen Wertes kann ein Reset der gespeicherten Consumption der relevanten Stunde durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
 set &amp;lt;Name&amp;gt; reset consumptionShort 07 21&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Die KI‑Verbrauchsprognose mit AI::FANN aktivieren und einstellen ===&lt;br /&gt;
&lt;br /&gt;
FANN steht für &#039;&#039;&#039;Fast Artificial Neural Network&#039;&#039;&#039;.&lt;br /&gt;
Es handelt sich um eine sehr schnelle, leichtgewichtige Open‑Source‑Bibliothek zur Erstellung und zum Training künstlicher neuronaler Netze. Ein Manual dieser Library ist [https://fann.sourceforge.net/reference/index.html hier] verfügbar.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* FANN ist die &#039;&#039;&#039;technische Grundlage&#039;&#039;&#039; der KI‑Verbrauchsprognose.&lt;br /&gt;
* ws berechnet aus historischen Verbrauchsdaten ein Modell, das zukünftige Werte vorhersagen kann.&lt;br /&gt;
* es ist &#039;&#039;&#039;robust, schnell und ressourcenschonend&#039;&#039;&#039;, ideal für Systeme, die regelmäßig neu trainiert werden müssen.&lt;br /&gt;
* FANN arbeitet mit klassischen Feed‑Forward‑Netzen und Backpropagation‑Training – also bewährten, stabilen Methoden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;AI::FANN&#039;&#039;&#039; ist ein Perl‑Modul, das als Schnittstelle (Binding) zwischen SolarForecast und der FANN‑Bibliothek dient.&lt;br /&gt;
&lt;br /&gt;
* AI::FANN ist die Brücke, über die unser Prognosesystem mit FANN kommuniziert.&lt;br /&gt;
* es ermöglicht dem System:&lt;br /&gt;
::* Trainingsdaten an FANN zu übergeben&lt;br /&gt;
::* ein neuronales Netz zu erzeugen&lt;br /&gt;
::* das Training zu steuern&lt;br /&gt;
::* das fertige Modell zu speichern und später für Prognosen zu nutzen&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Voraussetzungen ====&lt;br /&gt;
&lt;br /&gt;
===== Installation der FANN‑Library (Linux) ===== &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt-get update &amp;amp;&amp;amp; sudo apt-get upgrade&lt;br /&gt;
sudo apt-get install gcc&lt;br /&gt;
sudo apt-get install libfann-dev libfann2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RPM‑basierte Systeme:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo dnf install fann-devel&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RPM‑basierte Systeme sind Linux‑Distributionen, die das Paketformat RPM (Red Hat Package Manager) verwenden.&lt;br /&gt;
&lt;br /&gt;
Typische RPM‑basierte Linux‑Distributionen:&lt;br /&gt;
* Red Hat Enterprise Linux (RHEL)&lt;br /&gt;
* CentOS / CentOS Stream&lt;br /&gt;
* Fedora&lt;br /&gt;
* openSUSE / SUSE Linux Enterprise&lt;br /&gt;
* Rocky Linux&lt;br /&gt;
* AlmaLinux&lt;br /&gt;
* Mageia&lt;br /&gt;
&lt;br /&gt;
===== Installation der FANN‑Library (Windows) ===== &lt;br /&gt;
&lt;br /&gt;
* der Installations- bzw. Erstellungsprozess der dll ist [https://fann.sourceforge.net/reference/x26.html hier] beschrieben &lt;br /&gt;
* fann.dll in PATH oder FHEM‑Verzeichnis kopieren  &lt;br /&gt;
* Perl‑Installation muss DLL laden können&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Installation des Perl‑Moduls AI::FANN ===== &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cpan install AI::FANN&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auf Debian Linux Systemen kann das Modul auch mit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt-get install libai-fann-perl &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
installiert werden.&lt;br /&gt;
&lt;br /&gt;
Alternativ kann natürlich auch cpanm oder der [https://wiki.fhem.de/wiki/Meta#Der_FHEM_Installer FHEM Installer] verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Bestandteile der Machine-Learning (ML)‑Pipeline ====&lt;br /&gt;
&lt;br /&gt;
===== Datenaufbereitung ===== &lt;br /&gt;
&lt;br /&gt;
Die Datenaufbereitung ist der wichtigste Schritt jeder ML‑Pipeline, da sie die Qualität der Eingabedaten sicherstellt.&lt;br /&gt;
Schlechte oder unskalierte Daten führen fast immer zu schlechten Modellen.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Normalisierung / Skalierung&#039;&#039;&#039;  &lt;br /&gt;
:- ML‑Modelle benötigen Eingabewerte in vergleichbaren Größenordnungen.&lt;br /&gt;
:- Beispiel: PV‑Leistung (0–10 000 W) vs. Uhrzeit (0–23).&lt;br /&gt;
:- Ohne Normalisierung würden große Werte die kleinen dominieren.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Feature‑Engineering&#039;&#039;&#039;  &lt;br /&gt;
: Aus Rohdaten werden zusätzliche Merkmale erzeugt, die Muster besser sichtbar machen:&lt;br /&gt;
::- Lags: Verbrauch der letzten Minuten/Stunden&lt;br /&gt;
::- Deltas: Änderungen gegenüber vorherigen Zeitpunkten&lt;br /&gt;
::- Zeitmerkmale: Stunde, Wochentag, Feiertag&lt;br /&gt;
::- PV‑Prognosen: erwartete Erzeugung als Einflussfaktor&lt;br /&gt;
::- Saisonale Merkmale: Sommer/Winter, Temperatur&lt;br /&gt;
::- Semantik (Erstellung von Interaktionen)&lt;br /&gt;
::- Rolling‑Statistics&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
📊 &#039;&#039;Rolling‑Statistics&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
„Rolling“ bedeutet, dass die Kennzahlen nicht einmalig über den gesamten Datensatz berechnet werden, sondern gleitend über ein Zeitfenster (z. B. 24 h, 7 Tage, 100 Samples). So werden Trends, Drift, Modellverschlechterung oder saisonale Muster besser erkannt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Integration zusätzlicher Verbraucher&#039;&#039;&#039;&lt;br /&gt;
: Wärmepumpen oder E‑Autos erzeugen starke, unregelmäßige Peaks. &lt;br /&gt;
: Diese können als zusätzliche Features einfließen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Es wird umgesetzt:&#039;&#039;&#039;&lt;br /&gt;
* ✔ Normalisierung auf physikalische Grenzen (PV‑Maximalleistung, Hausverbrauchs‑Maxima)&lt;br /&gt;
* ✔ Feature‑Engineering wie Lags, Deltas, Rolling‑Statistics, Zeitmerkmale, PV/PV-Prognosen als Input und weitere Semantik&lt;br /&gt;
* ✔ Optionale Zusatzlasten (WP/EV)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Trainingsdaten‑Split ===== &lt;br /&gt;
&lt;br /&gt;
Der Split trennt Daten in Trainingsdaten (zum Lernen) und Validierungsdaten (zur Qualitätskontrolle).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Training&#039;&#039;&#039;  &lt;br /&gt;
: Das Modell lernt Muster aus historischen Daten.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Validierung&#039;&#039;&#039;  &lt;br /&gt;
: Das Modell wird auf Daten getestet, die es nicht gesehen hat.&lt;br /&gt;
: Dadurch erkennt man Overfitting.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Shuffling&#039;&#039;&#039;  &lt;br /&gt;
: Durchmischen der Daten, um Reihenfolgeeffekte zu vermeiden.&lt;br /&gt;
: Besonders wichtig bei Zeitreihen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Es wird umgesetzt:&#039;&#039;&#039;&lt;br /&gt;
* ✔ Training/Validierung‑Split&lt;br /&gt;
* ✔ Shuffling je nach Einstellung von aiControl-&amp;gt;aiConShuffleMode&lt;br /&gt;
* ✔ Shuffle‑Perioden während des Trainings&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Netzarchitektur ===== &lt;br /&gt;
&lt;br /&gt;
Die Architektur bestimmt, wie das neuronale Netz aufgebaut ist.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Inputs&#039;&#039;&#039;  &lt;br /&gt;
: Anzahl der Merkmale (Features), die das Modell erhält.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Hidden Layers&#039;&#039;&#039;  &lt;br /&gt;
: Anzahl und Größe der verdeckten Schichten bestimmen, wie komplexe Muster erkannt werden können.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Output Layer&#039;&#039;&#039;  &lt;br /&gt;
: bei SolarForecast: 1 Wert = Verbrauchsprognose (Wh).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Es wird umgesetzt:&#039;&#039;&#039;&lt;br /&gt;
* ✔ Dynamische Input‑Anzahl je nach aktivierten Features&lt;br /&gt;
* ✔ Konfigurierbare Hidden Layers (z. B. 80‑40‑20)&lt;br /&gt;
* ✔ 1 Output‑Neuron&lt;br /&gt;
* ✔ Konfigurierbare Aktivierungsfunktionen&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Training ===== &lt;br /&gt;
&lt;br /&gt;
Hier werden die Gewichte des Netzes angepasst, um Fehler zu minimieren.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Trainingsalgorithmus&#039;&#039;&#039;&lt;br /&gt;
: RPROP: stabil, robust&lt;br /&gt;
: INCREMENTAL: schneller, aber empfindlicher&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lernrate (Learning Rate)&#039;&#039;&#039;  &lt;br /&gt;
: Wie stark Gewichte pro Schritt angepasst werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Momentum&#039;&#039;&#039;  &lt;br /&gt;
: Glättet die Lernbewegung, verhindert Zickzack‑Verhalten.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Steepness&#039;&#039;&#039;  &lt;br /&gt;
: Steuert die Empfindlichkeit der Aktivierungsfunktion.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Shuffle‑Perioden&#039;&#039;&#039;  &lt;br /&gt;
: Wie oft die Trainingsdaten neu gemischt werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Early‑Stopping&#039;&#039;&#039;  &lt;br /&gt;
: Training wird beendet, wenn Validierungsfehler nicht mehr sinkt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Es wird umgesetzt:&#039;&#039;&#039;&lt;br /&gt;
* ✔ RPROP und INCREMENTAL&lt;br /&gt;
* ✔ Learning Rate, Momentum, Steepness konfigurierbar&lt;br /&gt;
* ✔ Shuffle‑Perioden&lt;br /&gt;
* ✔ Early‑Stopping über Validierungsfehler&lt;br /&gt;
* ✔ Mehrere Trainingsläufe (Runs) zur Modellselektion&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Modellselektion und Fehlerevaluierung ===== &lt;br /&gt;
&lt;br /&gt;
Hier wird entschieden, welches Modell am Ende verwendet wird. &lt;br /&gt;
Die Ergebnisse des Trainings werden während des Traininglaufs fortlaufend überwacht und die Einhaltung von intern vorgegebenen Kennzahlen von einem Retrain-Guard überprüft. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Evaluation&#039;&#039;&#039;&lt;br /&gt;
* MAE, MAPE, RMSE, R²&lt;br /&gt;
* BitFail&lt;br /&gt;
* Bias/Slope&lt;br /&gt;
* P95/P99&lt;br /&gt;
&lt;br /&gt;
📈 &#039;&#039;Fehlermaße: MAE, MAPE, RMSE, R²&#039;&#039;  &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;MAE&#039;&#039;&#039; – Mean Absolute Error (durchschnittlicher absoluter Fehler) &lt;br /&gt;
::: MAE=1/𝑛∑∣𝑦−𝑦&amp;lt;sup&amp;gt;^&amp;lt;/sup&amp;gt;∣&lt;br /&gt;
* &#039;&#039;&#039;MAPE&#039;&#039;&#039; – Mean Absolute Percentage Error (prozentualer Fehler)&lt;br /&gt;
::: MAPE=100/𝑛∑∣(𝑦−𝑦&amp;lt;sup&amp;gt;^&amp;lt;/sup&amp;gt;)/𝑦∣&lt;br /&gt;
::* Achtung: &#039;&#039;&#039;problematisch bei kleinen oder Null‑Werten&#039;&#039;&#039; (klassisch bei Verbrauchsdaten nachts).&lt;br /&gt;
* &#039;&#039;&#039;RMSE&#039;&#039;&#039; – Root Mean Squared Error (Quadratischer Fehler, stärker empfindlich für Ausreißer)&lt;br /&gt;
::* gut, wenn große Fehler besonders kritisch sind&lt;br /&gt;
* &#039;&#039;&#039;R²&#039;&#039;&#039; – Bestimmtheitsmaß (Anteil der Varianz, den das Modell erklärt)&lt;br /&gt;
::: 𝑅&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;=1−(SSE/SST)&lt;br /&gt;
::* 1.0 = perfekt, 0 = nicht besser als Mittelwert, &amp;lt;0 = schlechter als Mittelwert&lt;br /&gt;
* &#039;&#039;&#039;P95 / P99&#039;&#039;&#039; (Quantile) - Quantile beschreiben, wie groß der Fehler in den schlechtesten X % der Fälle ist.&lt;br /&gt;
::* &#039;&#039;&#039;P95:&#039;&#039;&#039; 95 % der Fehler liegen darunter → die schlechtesten 5 % sind größer&lt;br /&gt;
::* &#039;&#039;&#039;P99:&#039;&#039;&#039; 99 % der Fehler liegen darunter → zeigt Extremfehler&lt;br /&gt;
* &#039;&#039;&#039;Bias / Slope&#039;&#039;&#039; (Regression‑Diagnostik) - Diese beiden Werte stammen aus einer linearen Regression zwischen &#039;&#039;&#039;Vorhersage&#039;&#039;&#039; und &#039;&#039;&#039;Ist‑Wert&#039;&#039;&#039;.&lt;br /&gt;
::* Diese beiden Werte sind extrem hilfreich, um Modell‑Drift oder fehlerhafte Normalisierung zu erkennen.&lt;br /&gt;
::* Slope - Ideal: 1.0&lt;br /&gt;
:::* &amp;lt; 1 → Modell unterschätzt hohe Werte&lt;br /&gt;
:::* &amp;gt;= 1 → Modell überschätzt hohe Werte&lt;br /&gt;
:::* zeigt systematische Skalierungsfehler&lt;br /&gt;
::* Bias - Ideal: 0&lt;br /&gt;
:::* positiv → Modell sagt im Schnitt zu wenig vorher&lt;br /&gt;
:::* negativ → Modell sagt im Schnitt zu viel vorher&lt;br /&gt;
:::* zeigt systematische Verschiebung&lt;br /&gt;
* &#039;&#039;&#039;BitFail&#039;&#039;&#039;&lt;br /&gt;
::* FANN verwendet „BitFail“ als Zählwert, wie viele Ausgaben eines Samples „falsch“ sind. Ein Output gilt als falsch, wenn der Fehler größer ist als ein definierter BitFail‑Schwellwert (z. B. 0.35).&lt;br /&gt;
::* Bei Regressionen ist BitFail weniger aussagekräftig, aber:&lt;br /&gt;
:::- es zeigt, wie viele Samples „deutlich daneben“ liegen.&lt;br /&gt;
:::- gut zur schnellen Qualitätskontrolle während des Trainings.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird die geforderte Güte nicht erreicht, initiiert der Guard eine Wiederholung des Trainings bis zu einer maximalen Anzahl von Durchläufen.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Bestes Modell speichern&#039;&#039;&#039;  &lt;br /&gt;
: Das Modell mit dem niedrigsten Validierungsfehler wird ausgewählt.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Verwendung nur des besten Modells&#039;&#039;&#039;  &lt;br /&gt;
: Schlechtere Modelle werden verworfen.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Trainingsmodus ohne Prognose&#039;&#039;&#039;  &lt;br /&gt;
: Nützlich, wenn man nur trainieren, aber noch nicht prognostizieren möchte.&lt;br /&gt;
: einschalten mit aiControl -&amp;gt;aiConActivate=2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Es wird umgesetzt:&#039;&#039;&#039;&lt;br /&gt;
* ✔ Monitoring mit Fehlerevaluierung&lt;br /&gt;
* ✔ bestes Modell wird automatisch gespeichert&lt;br /&gt;
* ✔ Prognosen basieren ausschließlich auf dem besten Modell&lt;br /&gt;
* ✔ Trainingsmodus only möglich (aiConActivate=2)&lt;br /&gt;
* ✔ Ausgabe detaillierter Trainingsmetriken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Einstellbare Parameter über &#039;attr &amp;lt;Name&amp;gt; aiControl&#039; ====&lt;br /&gt;
&lt;br /&gt;
Die Einstellung von &#039;&#039;&#039;aiConActivate&#039;&#039;&#039;, &#039;&#039;&#039;aiConAlpha&#039;&#039;&#039; und &#039;&#039;&#039;aiConTrainStart&#039;&#039;&#039; wirken sofort, alle anderen Parameter werden erst beim nächsten Trainingslauf wirksam.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConActivate&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Wert !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| 0 || KI deaktiviert&lt;br /&gt;
|-&lt;br /&gt;
| 1 || KI aktiviert (Standard)&lt;br /&gt;
|-&lt;br /&gt;
| 2 || Trainingsmodus aktiv, die KI-Prognose ist deaktiviert. Es wird maximal eine Trainingswiederholung ausgeführt.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
* 1 ab 2000–3000 verfügbaren Datensätzen (siehe get &amp;lt;Name&amp;gt; valDecTree aiRawData), bei WP/EV &amp;gt; 5000&lt;br /&gt;
* Der Trainingsmodus dient dazu verschiedene Einstellungen testen zu können. Zur Zeitersparnis wird maximal eine Trainingswiederholung ausgeführt, unabhängig von der Güte des Trainingsergebisses&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConAlpha&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Mit diesem Parameter kann ein Hybridergebnis aus klassischen (Legacy‑)Prognosen und durch die KI ermittelten Prognosewerten erzeugt werden. Das Hybridergebnis wird durch eine prozentuale Mischung beider Resultate erstellt.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Wert !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| 0 || die KI-Ergebnisse werden nicht verwendet, nur Legacy Werte gehen in das finale Ergebnis ein&lt;br /&gt;
|-&lt;br /&gt;
| 0.x || die KI-Ergebnisse gehen zu 0.x * 100%, die Legacy Werte zu (1-0.x) * 100% in die finale Prognose ein &lt;br /&gt;
|-&lt;br /&gt;
| 1 || es werden ausschließlich KI-Ergebnisse verwendet, Legacy Werte gehen nicht in das finale Ergebnis ein&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
* 1 wenn die Genauigkeit der KI-Prognose überzeugend ist, ansonsten kann ein Mix aus KI und Legacy-Prognose hergestellt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConTrainStart&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Legt fest, wann das Modul ein atomatisches Erst- bzw. Folgetraining durchführt. Im Standard erfolgt das Training alle 7 Tage.&lt;br /&gt;
&lt;br /&gt;
Format: `&amp;lt;Tage&amp;gt;:&amp;lt;Stunde&amp;gt;`, z. B. `7:3`.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt; &lt;br /&gt;
* 7–14 Tage für normale Haushalte  &lt;br /&gt;
* 3–5 Tage bei WP/EV&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConActFunc&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funktion !! Eigenschaften&lt;br /&gt;
|-&lt;br /&gt;
| SIGMOID || + bewährt, stabil, gut für kontinuierliche, monotone Zusammenhänge&lt;br /&gt;
– kann bei großen Inputs saturieren, aber bei Verbrauchsprognose meistens gut&lt;br /&gt;
|-&lt;br /&gt;
| GAUSSIAN || + gut für glatte Muster &lt;br /&gt;
– schlecht für harte Peaks (EV, Trockner), kann „vergessen“ und saturieren&lt;br /&gt;
|-&lt;br /&gt;
| ELLIOT || + schnellere, numerisch robustere Approximation von Sigmoid/Tanh, weniger Rechenaufwand &lt;br /&gt;
+ oft etwas „härter“ in der Reaktion, kann Peaks besser durchreichen &amp;lt;br&amp;gt;&lt;br /&gt;
– immer noch S‑förmig, also keine Wunderwaffe gegen komplett unmodellierte EV‑Ereignisse&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt; &lt;br /&gt;
* SIGMOID oder SIGMOID_SYMMETRIC als Standard&lt;br /&gt;
* bei allen weiteren Aktivierungsfunktionen kommt es auf den Versuch an&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConHiddenLayers&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Typ !! Beispiel !! Eigenschaften&lt;br /&gt;
|-&lt;br /&gt;
| klein || 50‑25 || schnell, weniger genau&lt;br /&gt;
|-&lt;br /&gt;
| mittel || 64‑32 || guter Kompromiss&lt;br /&gt;
|-&lt;br /&gt;
| tief || 64‑32‑16 / 80‑40‑20 || erkennt komplexe Muster&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
* &amp;lt; 3000 verfügbaren Datensätzen → `50-25`  &lt;br /&gt;
* 3000–8000 verfügbaren Datensätzen → `64-32`  &lt;br /&gt;
* &amp;gt; 8000 verfügbaren Datensätzen oder WP/EV → `80-40-20`&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConLearnRate&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Wert !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| 0.001 || sehr stabil, langsam&lt;br /&gt;
|-&lt;br /&gt;
| 0.005 || guter Kompromiss&lt;br /&gt;
|-&lt;br /&gt;
| 0.01–0.05 || schnell, aber instabil&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
* 0.005, bei WP/EV 0.001&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConBitFailLimit&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Das Bit‑Fail‑Limit bestimmt, &#039;&#039;&#039;ab welcher Abweichung zwischen Prognose und echtem Wert&#039;&#039;&#039; ein Trainingspunkt als „Fehler“ gezählt wird.&lt;br /&gt;
Ein kleinerer Wert macht das Training &#039;&#039;&#039;strenger&#039;&#039;&#039;, ein größerer Wert macht es &#039;&#039;&#039;toleranter&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;kleineres Limit → Modell versucht Peaks stärker zu treffen&#039;&#039;&#039; → kann instabil werden, besonders mit INCREMENTAL&lt;br /&gt;
* &#039;&#039;&#039;größeres Limit → Modell glättet stärker&#039;&#039;&#039; → robuster, aber weniger peak‑sensitiv&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Wert !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| kleineres Limit (0.10–0.25) || Das Modell versucht Peaks und schnelle Änderungen genauer zu treffen, kann aber instabiler werden.&lt;br /&gt;
|-&lt;br /&gt;
| mittleres Limit (0.25–0.35) || Gute Balance zwischen Genauigkeit und Stabilität. Empfohlener Startbereich.&lt;br /&gt;
|-&lt;br /&gt;
| größeres Limit (0.35–0.50) || Das Modell wird robuster gegen Ausreißer und Rauschen, reagiert aber weniger stark auf Spitzenlasten.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
🌪️ &#039;&#039;&#039;Was bedeutet „verrauschter Haushalt“?&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Ein Haushalt gilt als „verrauscht“, wenn der Stromverbrauch viele kleine, unregelmäßige Schwankungen hat, die nicht durch klare Muster (z. B. PV, Wärmepumpe, feste Tagesabläufe) erklärbar sind.&lt;br /&gt;
Dazu gehören spontane Gerätewechsel, impulsartige Lasten oder allgemein unruhige Verbrauchsprofile.&lt;br /&gt;
&lt;br /&gt;
Für solche Haushalte ist ein höheres Bit‑Fail‑Limit sinnvoll, weil das Modell dadurch robuster wird und nicht versucht, jede kleine Zufallsschwankung exakt vorherzusagen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
* versuche deinen Haushalt gemäß der oben beschriebenen Rauscheigenschaft einzuordnen und entscheide dann, ob ein Training unterhalb oder oberhalb des Defaultwertes (0.35) bei dir sinnvoll sein könnte. Bleibe dann bei der Einstellung die bei dir die besten Ergebnisse liefert. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConMomentum&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bereich !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| 0.2 || reagiert direkt, schwankt stärker&lt;br /&gt;
|-&lt;br /&gt;
| 0.5–0.8 || stabil, guter Kompromiss&lt;br /&gt;
|-&lt;br /&gt;
| 0.9 || sehr stark geglättet&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
* 0.5, bei WP/EV 0.7–0.8&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConShuffleMode&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Wert !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| 0 || chronologisch&lt;br /&gt;
|-&lt;br /&gt;
| 1 || chronologischer Split + Shuffle&lt;br /&gt;
|-&lt;br /&gt;
| 2 || vollständiges Shuffle&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt; &lt;br /&gt;
* 2, bei saisonalen Mustern 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConShufflePeriod&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Wert !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| 10 || viel Variation&lt;br /&gt;
|-&lt;br /&gt;
| 15–20 || stabiler Kompromiss&lt;br /&gt;
|-&lt;br /&gt;
| &amp;gt;20 || Gefahr von Overfitting&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
* 10, bei großen Datensätzen 15–20&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConSteepness&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bereich !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;0.4 || starke Glättung&lt;br /&gt;
|-&lt;br /&gt;
| 0.5 || Standard&lt;br /&gt;
|-&lt;br /&gt;
| &amp;gt;0.7 || schärfere Muster&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt; &lt;br /&gt;
* 0.9, bei glattem Verbrauch 0.5&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConTrainAlgo&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Algorithmus !! Eigenschaften&lt;br /&gt;
|-&lt;br /&gt;
| RPROP || stabil, wenig Parameter&lt;br /&gt;
|-&lt;br /&gt;
| INCREMENTAL || schneller, empfindlicher&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt; &lt;br /&gt;
* RPROP bei WP/EV  &lt;br /&gt;
* INCREMENTAL bei einfachen Profilen&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConProfile&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die folgenden Profile bestimmen, welche Verbrauchslogiken und Semantiken im Modell aktiviert werden. Sie beeinflussen, wie stark das Modell auf typische Haushaltsaktivitäten, PV‑Erzeugung und Wärmepumpenverhalten reagiert.&lt;br /&gt;
&lt;br /&gt;
Damit Nutzer das passende Profil wählen können, sind die Profile hier verständlich beschrieben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Profil !! Eigenschaften&lt;br /&gt;
|-&lt;br /&gt;
| v1_common || Dieses Profil bildet den typischen menschlichen Tagesrhythmus ab:&lt;br /&gt;
* Morgenaktivität (Aufstehen, Geräte an)&lt;br /&gt;
* Mittagsaktivität (Kochen, Haushalt)&lt;br /&gt;
* Abendaktivität (Kochen, Licht, Geräte)&lt;br /&gt;
* Später Abend (Geräte gehen aus)&lt;br /&gt;
* Wochenendverhalten&lt;br /&gt;
* Tagesmuster vom Vortag&lt;br /&gt;
* Grundlast nachts&lt;br /&gt;
&lt;br /&gt;
Es nutzt Zeitstruktur, saisonale Muster, Wetter und Verbrauchsdynamik — aber &#039;&#039;&#039;keine PV‑ oder Wärmepumpenlogik&#039;&#039;&#039;. &amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Empfohlen für:&#039;&#039;&#039; &lt;br /&gt;
Haushalte mit reinem Stromverbrauch ohne besondere Geräte und wenig PV Einfluß, z.B. mit kleiner Balkon PV-Anlage.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| v1_common_active || Für &#039;&#039;&#039;Haushalte mit stark ausgeprägten Aktivitätsmustern&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Wie &#039;&#039;v1_common&#039;&#039;, aber mit stärkerer Betonung auf:&lt;br /&gt;
* Verbrauchssprüngen&lt;br /&gt;
* Trendbrüchen&lt;br /&gt;
* Volatilität (z. B. Kochen, Gerätewechsel)&lt;br /&gt;
* Wiederkehrenden Peaks&lt;br /&gt;
&lt;br /&gt;
Dieses Profil reagiert sensibler auf &#039;&#039;&#039;kurzfristige Verbrauchsdynamik&#039;&#039;&#039;. &amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Empfohlen für:&#039;&#039;&#039;  &lt;br /&gt;
Haushalte mit unregelmäßigen oder dynamischen Verbrauchsprofilen (z.B. viele Geräte, Homeoffice, Familien).&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| v1_common_pv || Für &#039;&#039;&#039;Haushalte mit PV-getriebenen Verbrauchern&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Erweitert &#039;&#039;v1_common&#039;&#039; um PV‑Semantik:&lt;br /&gt;
* PV‑Erzeugung + Tageszeit&lt;br /&gt;
* PV‑Drop‑Erkennung (Wolke → Lastabfall)&lt;br /&gt;
* PV‑abhängige Verbrauchsverschiebung&lt;br /&gt;
* PV‑Mittagsspitzen‑Verstärker&lt;br /&gt;
* PV‑Temperatur‑Interaktionen (Heizung, Batterie, Geräteverhalten)&lt;br /&gt;
&lt;br /&gt;
Das Modell versteht, dass Haushalte &#039;&#039;&#039;mittags anders verbrauchen&#039;&#039;&#039;, wenn PV‑Strom verfügbar ist. &amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Empfohlen für:&#039;&#039;&#039;  &lt;br /&gt;
Haushalte mit größerer PV‑Anlage, aber ohne Wärmepumpe.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| v1_common_active_pv || Für &#039;&#039;&#039;Haushalte mit dynamisch PV-getriebenen Verbrauchsverhalten&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Kombiniert: &lt;br /&gt;
* Dynamik‑Semantik aus v1_common_active&lt;br /&gt;
* PV‑Semantik aus v1_common_pv&lt;br /&gt;
&lt;br /&gt;
Dieses Profil erkennt:&lt;br /&gt;
* spontane Peaks bei PV‑Überschuss&lt;br /&gt;
* Verbrauchssprünge + PV‑Erzeugung&lt;br /&gt;
* Trendverstärker mittags&lt;br /&gt;
* PV‑Drop‑Reaktionen&lt;br /&gt;
* Volatilität + PV‑Interaktionen&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Empfohlen für:&#039;&#039;&#039;  &lt;br /&gt;
PV‑Haushalte mit aktiven Verbrauchern (z.B. Kochen, Waschmaschine, Trockner usw.).&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| v1_heatpump || Für &#039;&#039;&#039;Haushalte mit Wärmepumpe (ohne dominante PV)&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Aktiviert die komplette Wärmepumpen‑Semantik:&lt;br /&gt;
* Heizmodus, Kühlmodus&lt;br /&gt;
* Warmwasser (morgens/abends, Zyklen, Kaltstart)&lt;br /&gt;
* Frostschutz&lt;br /&gt;
* Temperaturtrends&lt;br /&gt;
* Effizienzindikatoren (COP‑Proxy)&lt;br /&gt;
* Heiz‑/Kühlbedarf&lt;br /&gt;
* Temperaturdeltas und -historie&lt;br /&gt;
&lt;br /&gt;
Das Modell versteht typische WP‑Verbrauchsmuster:&lt;br /&gt;
* morgens und abends Heizen&lt;br /&gt;
* Warmwasserzyklen&lt;br /&gt;
* Frostschutz nachts&lt;br /&gt;
* Reaktion auf Temperaturstürze&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Empfohlen für:&#039;&#039;&#039;  &lt;br /&gt;
Haushalte mit Wärmepumpe, aber ohne dominante PV.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| v1_heatpump_pv || Für &#039;&#039;&#039;Wärmepumpen‑Haushalte mit dominanter PV&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Kombiniert:&lt;br /&gt;
* Wärmepumpen‑Semantik&lt;br /&gt;
* PV‑Semantik&lt;br /&gt;
* PV‑Warmwasser‑Boost&lt;br /&gt;
* PV‑Mittagsverschiebung&lt;br /&gt;
* PV‑abhängige Heiz-/WW‑Strategien&lt;br /&gt;
* Das Modell erkennt:&lt;br /&gt;
* PV‑Überschuss → Warmwasser&lt;br /&gt;
* PV‑Erzeugung → Heiz-/Kühlverhalten&lt;br /&gt;
* PV‑Drop → Lastabfall&lt;br /&gt;
* PV + Kälte → Heizspitzen&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Empfohlen für:&#039;&#039;&#039;  &lt;br /&gt;
Haushalte mit Wärmepumpe und dominanter PV‑Anlage.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| v1_heatpump_active_pv || Für &#039;&#039;&#039;Wärmepumpe + PV + dynamisches Verbrauchsverhalten&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Das umfassendste Profil. Es kombiniert:&lt;br /&gt;
* Wärmepumpen‑Semantik&lt;br /&gt;
* PV‑Semantik&lt;br /&gt;
* Dynamik‑Semantik (Trend, Volatilität, Peaks)&lt;br /&gt;
* Spezial‑Booster (z. B. heatpump_boost_special, pv_mittag_peak_boost_special)&lt;br /&gt;
&lt;br /&gt;
Dieses Profil erkennt:&lt;br /&gt;
* spontane Verbrauchssprünge&lt;br /&gt;
* WP‑Zyklen + PV‑Überschuss&lt;br /&gt;
* Trendbrüche + Temperaturdeltas&lt;br /&gt;
* dynamische Mittagspeaks&lt;br /&gt;
* komplexe Interaktionen zwischen PV, WP und menschlichem Verhalten&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Empfohlen für:&#039;&#039;&#039;  &lt;br /&gt;
Haushalte mit Wärmepumpe, PV und sehr aktivem Verbrauchsverhalten.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|  || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Die oben angegebenen Profileigenschaften beschreiben die implementierten Verstärkungen bzw. auch Abschwächungen zur Unterstützung des Lernprozesses der künstlichen Intelligenz. Teste Trainings mit unterschiedlichen Profilen und wähle das Profil mit dem die besten Ergebnisse erzielt werden. Beginne mit dem Profil welches wahrscheinlich am Besten zu deinem Haushalt passen könnte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Integration von Umwelt- und Kontextfaktoren in die Prognose ====&lt;br /&gt;
&lt;br /&gt;
Die Verbrauchscharakteristik eines Haushalts wird nicht nur durch die eingesetzten elektrischen Geräte bestimmt, sondern auch durch verschiedene systemische Einflussfaktoren, darunter:&lt;br /&gt;
&lt;br /&gt;
* Anwesenheit bzw. Abwesenheit der Bewohner&lt;br /&gt;
* Außentemperaturen&lt;br /&gt;
* Abweichungen vom üblichen Tagesmuster, z.B. durch Feiertage oder Urlaubszeiten&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einbindung von Sensoren und Kontextdaten&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Außentemperatursensoren, Windsensoren sowie Geräte zur Anwesenheits- oder Bewegungsdetektion werden im Attribut &#039;&#039;&#039;setupEnvironment&#039;&#039;&#039; hinterlegt. Die dafür erforderliche Syntax ist in der Online‑Hilfe des Moduls dokumentiert. SolarForecast nutzt diese Informationen, um Verbrauchsprognosen an reale Rahmenbedingungen anzupassen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die erfassten Umweltdaten sind Momentanwerte, die – sofern sie eine ausreichende Dynamik aufweisen – auf das in SolarForecast verwendete Stundenraster normiert oder geglättet werden.&lt;br /&gt;
&lt;br /&gt;
::* &#039;&#039;&#039;Außentemperaturen:&#039;&#039;&#039; Temperaturen ändern sich vergleichsweise langsam und werden daher direkt übernommen. Ist kein Temperatursensor definiert, wird die Temperatur des verwendeten Wetterdienstes genutzt.&lt;br /&gt;
::* &#039;&#039;&#039;Anwesenheit:&#039;&#039;&#039; Für jede Stunde wird der Anwesenheitsstatus anhand des überwiegenden Zustands innerhalb dieser Stunde bestimmt.&lt;br /&gt;
::::- &#039;&#039;&#039;Beispiel:&#039;&#039;&#039; Verlassen die Bewohner das Haus erst zehn Minuten vor Ende der Stunde, würde eine reine Momentaufnahme den Status &#039;&#039;„abwesend“&#039;&#039; speichern. Da dies sachlich nicht zutrifft, wird der überwiegende Status der Stunde bewertet und gespeichert.&lt;br /&gt;
::* &#039;&#039;&#039;Windgeschwindigkeit:&#039;&#039;&#039; Zur Bewertung der Windverhältnisse werden zwei geglättete Windgeschwindigkeiten berechnet - eine &#039;&#039;&#039;schnelle&#039;&#039;&#039; und eine &#039;&#039;&#039;langsame&#039;&#039;&#039; Komponente. Beide verwenden &#039;&#039;&#039;exponentielles Glätten&#039;&#039;&#039;, bei dem neue Messwerte stärker gewichtet werden als ältere.&lt;br /&gt;
:::: - &#039;&#039;&#039;Fast (10 Minuten):&#039;&#039;&#039; Reagiert schnell auf kurzfristige Änderungen, z. B. durch vorbeiziehende Wolken.&lt;br /&gt;
:::: - &#039;&#039;&#039;Slow (40 Minuten):&#039;&#039;&#039; Spiegelt die Großwetterlage bzw. den längerfristigen Trend wider.&lt;br /&gt;
:::: Die Glättung erfolgt nach dem Prinzip: &lt;br /&gt;
:::::: &amp;lt;code&amp;gt; neuer Wert = α · aktueller Messwert + (1 − α) · vorheriger geglätteter Wert &amp;lt;/code&amp;gt;&lt;br /&gt;
:::: wobei &amp;lt;code&amp;gt;α&amp;lt;/code&amp;gt; abhängig von der jeweiligen Zeitkonstante berechnet wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Feiertage und Urlaubszeiten&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Berücksichtigung von Feiertagen und Urlaub wird das in FHEM etablierte Verfahren über [https://fhem.de/commandref_DE.html#holiday holiday]-Devices verwendet.&lt;br /&gt;
Dazu werden die entsprechenden holiday‑Devices im globalen Attribut &#039;&#039;holiday2we&#039;&#039; registriert. SolarForecast liest die dort eingetragenen holiday‑Devices aus und übernimmt die darin definierten Daten (z.B. gesetzliche Feiertage, benutzerdefinierte freie Tage oder Urlaubszeiträume).&lt;br /&gt;
&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Das Training durchführen und produktiv setzen (Best Practice Ansatz) ====&lt;br /&gt;
&lt;br /&gt;
Sind alle [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Voraussetzungen|Voraussetzungen]] erfüllt, kann das Verbauchsprognose-Modell trainiert und – sofern das Ergebnis überzeugt – für den Produktivbetrieb aktiviert werden. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1️⃣ &#039;&#039;&#039;Training‑Only‑Modus aktivieren&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für das initiale Training wird FANN im &#039;&#039;Training‑Only‑Modus&#039;&#039; aktiviert:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; aiControl aiConActivate=2&lt;br /&gt;
&lt;br /&gt;
In diesem Modus kann das Modell beliebig oft trainiert, bewertet und durch Anpassung der [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Einstellbare_Parameter_über_&#039;attr_&amp;lt;Name&amp;gt;_aiControl|Steuerungsparameter]] optimiert werden – ohne dass die produktive Prognose beeinflusst wird. Es kann jederzeit ein neues Training gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wer den Trainingsablauf und die internen Prüfungen live verfolgen möchte, aktiviert zusätzlich:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; ctrlDebug aiProcess&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2️⃣ &#039;&#039;&#039;Training starten&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Mit der FANN-Aktivierung durch aiControl aiConActivate=2 (oder 1) werden automatisch sinnvolle &#039;&#039;&#039;Standardparameter&#039;&#039;&#039; für FANN gesetzt. Für den Einstieg empfiehlt es sich, zunächst mit diesen Defaults zu trainieren und Änderungen an Parametern schrittweise vorzunehmen, neu zu trainieren und die Veränderungen im Ergebnis zu bewerten. Als Hilfestellung gibt es dazu einen separaten [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Auswertung_der_Trainingskennwerte|Abschnitt]]. &lt;br /&gt;
&lt;br /&gt;
Das Training wird manuell gestartet mit:&lt;br /&gt;
&lt;br /&gt;
 set &amp;lt;Name&amp;gt; aiDecTree runConTrain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Ein bereits laufendes Training wird durch einen erneuten Start mit &#039;&#039;runConTrain&#039;&#039; automatisch abgebrochen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ein laufendes Training kann jederzeit manuell beendet werden:&lt;br /&gt;
&lt;br /&gt;
 set &amp;lt;Name&amp;gt; aiDecTree stopConTrain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3️⃣ &#039;&#039;&#039;Wie das Training intern abläuft&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Der Trainingsprozess wird vollständig durch die interne Steuerungslogik des Moduls geführt:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Ein Trainingsjob umfasst &#039;&#039;&#039;bis zu 6 Trainingswiederholungen&#039;&#039;&#039;, jede mit &#039;&#039;&#039;maximal 15000&#039;&#039;&#039; Epochen.&lt;br /&gt;
* Ein &#039;&#039;&#039;Snapshot‑Guard&#039;&#039;&#039; überwacht kontinuierlich die Modellverbesserung und speichert bessere Modelle als Best Snapshot.&lt;br /&gt;
* Ein integrierter &#039;&#039;&#039;Early‑Stopping‑Mechanismus&#039;&#039;&#039; beendet Trainingsläufe, die sich nicht weiter verbessern.&lt;br /&gt;
* Ein interner &#039;&#039;&#039;Retrain‑Indikator&#039;&#039;&#039; bewertet den besten Snapshot. Ein &#039;&#039;&#039;Quality Gate&#039;&#039;&#039; entscheidet, ob ein weiterer Retrain durchgeführt wird.&lt;br /&gt;
* Die Anzahl der Retrains wird &#039;&#039;&#039;adaptiv&#039;&#039;&#039; anhand interner Kriterien bestimmt.&lt;br /&gt;
* Mit aktiviertem Debug‑Modus werden alle Entscheidungen im Log dokumentiert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der gesamte Prozess läuft in einem &#039;&#039;&#039;Nebenprozess&#039;&#039;&#039;, um FHEM nicht zu blockieren.&lt;br /&gt;
Je nach Hardware, Datenmenge und Parametern kann das Training sehr lange dauern – im Extremfall mehrere Stunden. Ein CPU‑Kern kann dabei dauerhaft zu 100 % ausgelastet sein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
4️⃣ &#039;&#039;&#039;Ergebnis bewerten&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Nach Abschluss des Trainings sollte das Ergebnis &#039;&#039;&#039;[[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Auswertung_der_Trainingskennwerte|manuell bewertet]]&#039;&#039;&#039; werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtige Hinweise:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
* Auch bei &#039;&#039;&#039;nicht perfekten Kennzahlen&#039;&#039;&#039; lohnt sich eine visuelle Prüfung.&lt;br /&gt;
* Auch bei &#039;&#039;&#039;zu perfekten Kennzahlen&#039;&#039;&#039; ist Vorsicht geboten – dies kann auf Overfitting hindeuten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
5️⃣ &#039;&#039;&#039;Modell produktiv setzen&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zur visuellen Begutachtung und für den Produktivbetrieb wird das trainierte Modell aktiviert:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; aiControl aiConActivate=1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Im nächsten Zyklus des Moduls (siehe &#039;attr ... plantControl cycleInterval&#039;) erscheinen die KI‑Prognosen in der Balkengrafik, sofern diese Ansicht aktiviert ist. Wenn die Prognose zufriedenstellend ist, bleibt das Modell aktiv. Falls nicht, kann jederzeit wieder in den &#039;&#039;Training‑Only&#039;&#039;‑Modus gewechselt werden, um Parameter anzupassen und erneut zu trainieren.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
6️⃣ &#039;&#039;&#039;Automatisches (Re)Training&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Bei aktivem FANN‑Modus (aiConActivate=1 oder 2) wird automatisch alle &#039;&#039;&#039;7 Tage um 03:00 Uhr&#039;&#039;&#039; ein Retraining durchgeführt.&lt;br /&gt;
Der Zeitpunkt kann angepasst werden:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; aiControl aiConTrainStart ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
7️⃣ &#039;&#039;&#039;Hybrid‑Modus&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Das Modul unterstützt einen &#039;&#039;&#039;Hybrid‑Modus&#039;&#039;&#039;, bei dem KI‑Prognosen mit den klassischen (Legacy‑)Prognosen gewichtet kombiniert werden. &lt;br /&gt;
Gesteuert wird dieser Modus über:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; aiControl aiConAlpha &amp;lt;Wert&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ein höherer Wert von [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Einstellbare_Parameter_über_&#039;attr_&amp;lt;Name&amp;gt;_aiControl&#039;|&#039;&#039;&#039;aiConAlpha&#039;&#039;&#039;]] bedeutet stärkere Gewichtung der KI‑Prognose.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
8️⃣ &#039;&#039;&#039;Debug‑Log&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für eine detaillierte Nachvollziehbarkeit des Trainingsprozesses kann der Debug‑Modus aktiviert werden.&lt;br /&gt;
Im Debug‑Log protokolliert das Modul sämtliche Schritte der Trainingslogik, darunter:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Start und Ende einzelner Trainingsläufe&lt;br /&gt;
* Verbesserungen der Modellgüte&lt;br /&gt;
* Snapshot‑Updates&lt;br /&gt;
* Early‑Stopping‑Ereignisse&lt;br /&gt;
* Entscheidungen des Quality Gates&lt;br /&gt;
* Auslösung von Retrains&lt;br /&gt;
* Abschlussbewertung des besten Modells&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dies erleichtert sowohl die Diagnose ungewöhnlicher Trainingsverläufe als auch die Bewertung, ob Parameteranpassungen sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible mw-collapsed&amp;quot;&amp;gt;&lt;br /&gt;
Ein &#039;&#039;&#039;auszugsweises Beispiel&#039;&#039;&#039; eines Trainingslogs -&amp;gt; &amp;lt;div class=&amp;quot;mw-collapsible-content&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
2026.01.01 15:40:06.690 1: SolCast DEBUG&amp;gt; First attempt 0 with Seed=407496&lt;br /&gt;
2026.01.01 15:40:06.696 1: SolCast DEBUG&amp;gt; AI FANN Training started with Params:&lt;br /&gt;
num input datasets=7931, &lt;br /&gt;
training algo=FANN_TRAIN_INCREMENTAL, &lt;br /&gt;
output AF=LINEAR, &lt;br /&gt;
hidden AF=SIGMOID, &lt;br /&gt;
hidden Neurons=80,40,20, &lt;br /&gt;
hidden steepness=0.9, &lt;br /&gt;
Epoches=15000, &lt;br /&gt;
mse_error=0.001, &lt;br /&gt;
learning rate=0.00500, &lt;br /&gt;
learning momentum=0.5, &lt;br /&gt;
Data sharing=split after shuffle of training data and use AI internal shuffle (Train=6344, Test=1586), &lt;br /&gt;
Data shuffle=2 (period=10)&lt;br /&gt;
2026.01.01 15:40:06.818 1: SolCast DEBUG&amp;gt; Epoche 1: Train MSE=0.001532, Val MSE=0.002521, Val MAE=0.028206, Val MedAE=0.020769, Bit_Fail=5 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 15:40:07.534 1: SolCast DEBUG&amp;gt; Epoche 8: Train MSE=0.001472, Val MSE=0.002520, Val MAE=0.028199, Val MedAE=0.020764, Bit_Fail=5 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 15:40:13.541 1: SolCast DEBUG&amp;gt; Epoche 67: Train MSE=0.001477, Val MSE=0.002518, Val MAE=0.026941, Val MedAE=0.018749, Bit_Fail=5 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 15:40:13.748 1: SolCast DEBUG&amp;gt; Epoche 69: Train MSE=0.001476, Val MSE=0.002517, Val MAE=0.026928, Val MedAE=0.018728, Bit_Fail=5 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
...&lt;br /&gt;
2026.01.01 15:40:21.048 1: SolCast DEBUG&amp;gt; Epoche 140: Train MSE=0.001181, Val MSE=0.002253, Val MAE=0.023585, Val MedAE=0.012176, Bit_Fail=5 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 15:40:27.191 1: SolCast DEBUG&amp;gt; Epoche 200: Train MSE=0.001181, Val MSE=0.001860, Val MAE=0.022984, Val MedAE=0.012926, Bit_Fail=4&lt;br /&gt;
2026.01.01 15:40:27.704 1: SolCast DEBUG&amp;gt; Epoche 205: Train MSE=0.000982, Val MSE=0.001821, Val MAE=0.022794, Val MedAE=0.012760, Bit_Fail=4 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 15:40:29.356 1: SolCast DEBUG&amp;gt; Epoche 221: Train MSE=0.000894, Val MSE=0.001654, Val MAE=0.021991, Val MedAE=0.012736, Bit_Fail=4 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
...&lt;br /&gt;
2026.01.01 15:40:30.508 1: SolCast DEBUG&amp;gt; Epoche 232: Train MSE=0.000806, Val MSE=0.001516, Val MAE=0.020531, Val MedAE=0.011495, Bit_Fail=4 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 15:40:30.615 1: SolCast DEBUG&amp;gt; Epoche 233: Train MSE=0.000797, Val MSE=0.001498, Val MAE=0.020435, Val MedAE=0.011480, Bit_Fail=2 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 15:40:30.722 1: SolCast DEBUG&amp;gt; Epoche 234: Train MSE=0.000787, Val MSE=0.001479, Val MAE=0.020336, Val MedAE=0.011380, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 15:40:30.829 1: SolCast DEBUG&amp;gt; Epoche 235: Train MSE=0.000777, Val MSE=0.001460, Val MAE=0.020232, Val MedAE=0.011321, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
...&lt;br /&gt;
2026.01.01 15:40:34.103 1: SolCast DEBUG&amp;gt; Epoche 266: Train MSE=0.000347, Val MSE=0.000621, Val MAE=0.015564, Val MedAE=0.010886, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 15:40:34.209 1: SolCast DEBUG&amp;gt; Epoche 267: Train MSE=0.000336, Val MSE=0.000598, Val MAE=0.015326, Val MedAE=0.010661, Bit_Fail=0 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 15:40:34.322 1: SolCast DEBUG&amp;gt; Epoche 268: Train MSE=0.000325, Val MSE=0.000576, Val MAE=0.015095, Val MedAE=0.010564, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 15:40:34.431 1: SolCast DEBUG&amp;gt; Epoche 269: Train MSE=0.000314, Val MSE=0.000555, Val MAE=0.014870, Val MedAE=0.010315, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
...&lt;br /&gt;
2026.01.01 15:45:53.259 1: SolCast DEBUG&amp;gt; Epoche 3300: Train MSE=0.000188, Val MSE=0.000286, Val MAE=0.011095, Val MedAE=0.007725, Bit_Fail=0&lt;br /&gt;
2026.01.01 15:46:00.439 1: SolCast DEBUG&amp;gt; Early stopping bei Epoche 3368 (no improvement since 2000 epochs)&lt;br /&gt;
2026.01.01 15:46:00.439 1: === Snapshot-Statistik ===&lt;br /&gt;
2026.01.01 15:46:00.440 1: Metric-Improvement Snapshots: 67 (letzte Epoche: 1368)&lt;br /&gt;
2026.01.01 15:46:00.440 1: Bit-Improvement Snapshots:    5 (letzte Epoche: 267)&lt;br /&gt;
2026.01.01 15:46:00.441 1: Bit-Tradeoff Snapshots:       0 (letzte Epoche: 0)&lt;br /&gt;
2026.01.01 15:46:00.443 1: SolCast DEBUG&amp;gt; Best Snapshot reloaded from Epoche 1368: Train MSE=0.000188, Val MSE=0.000286, Val MAE=0.010789, Val MedAE=0.006938, Bit_Fail=0,&lt;br /&gt;
2026.01.01 15:46:00.444 1: SolCast DEBUG&amp;gt; Run Validation Test with 20% of Input data ...&lt;br /&gt;
2026.01.01 15:46:00.475 1: SolCast DEBUG&amp;gt; Validation finished - Best Training MSE=0.000188, Validation MSE=0.000286, Validation Bit_Fail=0&lt;br /&gt;
2026.01.01 15:46:00.476 1: SolCast DEBUG&amp;gt; Retrain check -&amp;gt; &lt;br /&gt;
-- In Normalization Space: -- &lt;br /&gt;
Train MSE=0.000188 &lt;br /&gt;
Val MSE=0.000286 &lt;br /&gt;
Val Mean=0.0002908456 &lt;br /&gt;
VAL/TRAIN MSE Ratio=1.525656 (limit=2.5) &lt;br /&gt;
Diff=0.000099 (limit=0.005) &lt;br /&gt;
ValStd=0.0000052738 (limit=7.27113936211133e-05) &lt;br /&gt;
-- At Original Scale: -- &lt;br /&gt;
MAE=96.4264081498789 &lt;br /&gt;
RMSE/MAE=1.5680 (limit=1.5) &lt;br /&gt;
Slope=0.846171 (limit=0.7 .. 1.3) &lt;br /&gt;
Bias=104.79 (limit=+-48.2132040749395) &lt;br /&gt;
R2=0.886437100872621 &lt;br /&gt;
P95=283.1830 (limit=385.705632599516) &lt;br /&gt;
P99=538.2559 (limit=771.411265199031) &lt;br /&gt;
-- Robustness Indicators: -- &lt;br /&gt;
RMSE relative=24 (limit=20) &lt;br /&gt;
BitFail=0 (limit=5) &lt;br /&gt;
BitFailRate=0.0000 (limit=0.1) &lt;br /&gt;
-&amp;gt; Retrain&lt;br /&gt;
&amp;lt;/pre&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;div class=&amp;quot;mw-collapsible mw-collapsed&amp;quot;&amp;gt;&lt;br /&gt;
Ein &#039;&#039;&#039;komplettes Beispiel mit 3 Wiederholungen&#039;&#039;&#039; eines Trainingslogs -&amp;gt; &amp;lt;div class=&amp;quot;mw-collapsible-content&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
2026.01.01 18:03:45.037 1: SolCast DEBUG&amp;gt; AI FANN Training for Consumption Forecast BlockingCall PID &amp;quot;813631&amp;quot; with Timeout 86400 s started&lt;br /&gt;
2026.01.01 18:03:46.046 1: SolCast DEBUG&amp;gt; AI FANN - There are 503 Records skipped due to incomplete or invalid data. Index: &lt;br /&gt;
2025013115, 2025020401, 2025020414, 2025020415, 2025020416, 2025021813, 2025021816, 2025021913, 2025021914, 2025021915, 2025022013, 2025022316, 2025030216, 2025030310, 2025030315, 2025030316, 2025030416, 2025030511, 2025030512, 2025030516, 2025030517, 2025030610, 2025030611, 2025030612, 2025030616, 2025030710, 2025030711, 2025030712, 2025030713, 2025030716, 2025030810, 2025030910, 2025030916, 2025030917, 2025031010, 2025031114, 2025031519, 2025031609, 2025031709, 2025031710, 2025031716, 2025031717, 2025031810, 2025031811, 2025031814, 2025031815, 2025031816, 2025031817, 2025031909, 2025031910, 2025031911, 2025031915, 2025031916, 2025031917, 2025032010, 2025032011, 2025032014, 2025032015, 2025032016, 2025032017, 2025032110, 2025032114, 2025032115, 2025032116, 2025032117, 2025032209, 2025032210, 2025032211, 2025032214, 2025032215, 2025032814, 2025032815, 2025032817, 2025033003, 2025040211, 2025040212, 2025040215, 2025040216, 2025040217, 2025040314, 2025040315, 2025040316, 2025040317, 2025040318, 2025040410, 2025040411, 2025040413, 2025040414, 2025040418, 2025040510, 2025040517, 2025040518, 2025040612, 2025040617, 2025040618, 2025040711, 2025040811, 2025040812, 2025040813, 2025041017, 2025041018, 2025041110, 2025041111, 2025041216, 2025041217, 2025041218, 2025041312, 2025041316, 2025041317, 2025041417, 2025041418, 2025041611, 2025041617, 2025041618, 2025042017, 2025042018, 2025042115, 2025042117, 2025042118, 2025042218, 2025042609, 2025042610, 2025042611, 2025042612, 2025042617, 2025042618, 2025042710, 2025042711, 2025042712, 2025042714, 2025042715, 2025042717, 2025042718, 2025042810, 2025042811, 2025042813, 2025042814, 2025042817, 2025042818, 2025042911, 2025042913, 2025042914, 2025042917, 2025042918, 2025050110, 2025050111, 2025050114, 2025050117, 2025050118, 2025050210, 2025050211, 2025050213, 2025050518, 2025050610, 2025050611, 2025050614, 2025050617, 2025050618, 2025050706, 2025050707, 2025050708, 2025050810, 2025050812, 2025050816, 2025050817, 2025050910, 2025050911, 2025050912, 2025050917, 2025050918, 2025051009, 2025051010, 2025051011, 2025051012, 2025051017, 2025051018, 2025051109, 2025051210, 2025051211, 2025051212, 2025051213, 2025051214, 2025051218, 2025051310, 2025051313, 2025051314, 2025051317, 2025051318, 2025051411, 2025051413, 2025051414, 2025051418, 2025051510, 2025051610, 2025051611, 2025051710, 2025051713, 2025051916, 2025052010, 2025052011, 2025052017, 2025052018, 2025052111, 2025052113, 2025052114, 2025052115, 2025052118, 2025052211, 2025052409, 2025052410, 2025052416, 2025052417, 2025052609, 2025052616, 2025052617, 2025052618, 2025052817, 2025052910, 2025052911, 2025052917, 2025053010, 2025053013, 2025053017, 2025053018, 2025053109, 2025053110, 2025053111, 2025053112, 2025053113, 2025053115, 2025053117, 2025060210, 2025060215, 2025060217, 2025060310, 2025060312, 2025060317, 2025060318, 2025060513, 2025060517, 2025060609, 2025060610, 2025060618, 2025060710, 2025060711, 2025060712, 2025060713, 2025060811, 2025060812, 2025060816, 2025060817, 2025060818, 2025060909, 2025060910, 2025060911, 2025060912, 2025060913, 2025060917, 2025060918, 2025061015, 2025061016, 2025061109, 2025061114, 2025061117, 2025061118, 2025061119, 2025061209, 2025061210, 2025061211, 2025061212, 2025061213, 2025061214, 2025061215, 2025061217, 2025061218, 2025061309, 2025061310, 2025061311, 2025061312, 2025061313, 2025061314, 2025061315, 2025061317, 2025061318, 2025061319, 2025061410, 2025061411, 2025061413, 2025061414, 2025061417, 2025061418, 2025061710, 2025061713, 2025061714, 2025061717, 2025061718, 2025061724, 2025062010, 2025062011, 2025062013, 2025062014, 2025062017, 2025062018, 2025062109, 2025062110, 2025062111, 2025062112, 2025062114, 2025062117, 2025062118, 2025062209, 2025062210, 2025062211, 2025062212, 2025062213, 2025062214, 2025062217, 2025062218, 2025062309, 2025062310, 2025062311, 2025062317, 2025062318, 2025062409, 2025062410, 2025062411, 2025062818, 2025062911, 2025062913, 2025062918, 2025063009, 2025063011, 2025063013, 2025063014, 2025063017, 2025063018, 2025070110, 2025070111, 2025070112, 2025070113, 2025070117, 2025070118, 2025070210, 2025070211, 2025070212, 2025070213, 2025070217, 2025070218, 2025070318, 2025070410, 2025070411, 2025070412, 2025070417, 2025070418, 2025070510, 2025070511, 2025070512, 2025070610, 2025070611, 2025070615, 2025070717, 2025070810, 2025071013, 2025071017, 2025071112, 2025071113, 2025071117, 2025071311, 2025071318, 2025071410, 2025071411, 2025071812, 2025071818, 2025071910, 2025071911, 2025071912, 2025071913, 2025071918, 2025072009, 2025072510, 2025072514, 2025073110, 2025073118, 2025080118, 2025080210, 2025080310, 2025080410, 2025080417, 2025080418, 2025080616, 2025080617, 2025080715, 2025080716, 2025080717, 2025080718, 2025080917, 2025080918, 2025081015, 2025081016, 2025081017, 2025081018, 2025081115, 2025081116, 2025081117, 2025081118, 2025081120, 2025081121, 2025081122, 2025081123, 2025081124, 2025081215, 2025081216, 2025081217, 2025081315, 2025081316, 2025081317, 2025081318, 2025081415, 2025081416, 2025081417, 2025081418, 2025081516, 2025081517, 2025081617, 2025081816, 2025081817, 2025081818, 2025081915, 2025081916, 2025081917, 2025082015, 2025082016, 2025082017, 2025082018, 2025082115, 2025082116, 2025082117, 2025082416, 2025082516, 2025082517, 2025082518, 2025082519, 2025082612, 2025082613, 2025082614, 2025082618, 2025082716, 2025082717, 2025083110, 2025083111, 2025083113, 2025083118, 2025090110, 2025090215, 2025090311, 2025090317, 2025090411, 2025090414, 2025090417, 2025090517, 2025090610, 2025090611, 2025090612, 2025090618, 2025090710, 2025090711, 2025090713, 2025090714, 2025090718, 2025090810, 2025090813, 2025090910, 2025090911, 2025091217, 2025091816, 2025091817, 2025091915, 2025091916, 2025091917, 2025092014, 2025092015, 2025092016, 2025092017, 2025092113, 2025092115, 2025092315, 2025092316, 2025092417, 2025092910, 2025092911, 2025092912, 2025092917, 2025093011, 2025093012, 2025093013, 2025093017, 2025100316, 2025100317, 2025110320, 2025122222, 2025122223, 2025122224, 2025122510&lt;br /&gt;
2026.01.01 18:03:46.940 1: SolCast - DBG F[7300]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.942 1: SolCast - DBG F[7301]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.944 1: SolCast - DBG F[7302]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.945 1: SolCast - DBG F[7303]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.947 1: SolCast - DBG F[7304]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.949 1: SolCast - DBG F[7305]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.951 1: SolCast - DBG F[7306]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.953 1: SolCast - DBG F[7307]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.954 1: SolCast - DBG F[7308]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.956 1: SolCast - DBG F[7309]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.958 1: SolCast - DBG F[7310]: lag1=0.002 lag2=0.001 lag24=0.002 d1p=0.036 d1n=0.000 rollstd=0.000 up=1 down=0 upS=0.036 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.960 1: SolCast - DBG F[7311]: lag1=0.026 lag2=0.002 lag24=0.008 d1p=0.004 d1n=0.000 rollstd=0.033 up=0 down=0 upS=0.004 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.962 1: SolCast - DBG F[7312]: lag1=0.029 lag2=0.026 lag24=0.012 d1p=0.000 d1n=0.008 rollstd=0.044 up=0 down=1 upS=0.000 downS=0.008 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.963 1: SolCast - DBG F[7313]: lag1=0.023 lag2=0.029 lag24=0.016 d1p=0.011 d1n=0.000 rollstd=0.045 up=1 down=0 upS=0.011 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.965 1: SolCast - DBG F[7314]: lag1=0.031 lag2=0.023 lag24=0.018 d1p=0.000 d1n=0.003 rollstd=0.044 up=0 down=0 upS=0.000 downS=0.003 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.967 1: SolCast - DBG F[7315]: lag1=0.028 lag2=0.031 lag24=0.017 d1p=0.002 d1n=0.000 rollstd=0.036 up=0 down=0 upS=0.002 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.968 1: SolCast - DBG F[7316]: lag1=0.030 lag2=0.028 lag24=0.008 d1p=0.000 d1n=0.002 rollstd=0.009 up=0 down=0 upS=0.000 downS=0.002 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.970 1: SolCast - DBG F[7317]: lag1=0.028 lag2=0.030 lag24=0.002 d1p=0.000 d1n=0.005 rollstd=0.009 up=0 down=1 upS=0.000 downS=0.005 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.974 1: SolCast - DBG F[7318]: lag1=0.025 lag2=0.028 lag24=0.002 d1p=0.005 d1n=0.000 rollstd=0.010 up=1 down=0 upS=0.005 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.976 1: SolCast - DBG F[7319]: lag1=0.028 lag2=0.025 lag24=0.001 d1p=0.008 d1n=0.000 rollstd=0.007 up=1 down=0 upS=0.008 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:47.013 1: SolCast DEBUG&amp;gt; First attempt 0 with Seed=439288&lt;br /&gt;
2026.01.01 18:03:47.024 1: SolCast DEBUG&amp;gt; AI FANN Training started with Params:&lt;br /&gt;
num input datasets=7314, &lt;br /&gt;
training algo=FANN_TRAIN_INCREMENTAL, &lt;br /&gt;
output AF=LINEAR, &lt;br /&gt;
hidden AF=SIGMOID, &lt;br /&gt;
hidden Neurons=80,40,20, &lt;br /&gt;
hidden steepness=0.9, &lt;br /&gt;
Epoches=15000, &lt;br /&gt;
mse_error=0.001, &lt;br /&gt;
learning rate=0.00500, &lt;br /&gt;
learning momentum=0.7, &lt;br /&gt;
Data sharing=split after shuffle of training data and use AI internal shuffle (Train=5851, Test=1462), &lt;br /&gt;
Data shuffle=2 (period=10)&lt;br /&gt;
2026.01.01 18:03:47.208 1: SolCast DEBUG&amp;gt; Epoche 1: Train MSE=0.002194, Val MSE=0.002834, Val MAE=0.031901, Val MedAE=0.027985, Bit_Fail=2 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:03:47.528 1: SolCast DEBUG&amp;gt; Epoche 3: Train MSE=0.002192, Val MSE=0.002833, Val MAE=0.031892, Val MedAE=0.027975, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:03:54.175 1: SolCast DEBUG&amp;gt; Epoche 48: Train MSE=0.001736, Val MSE=0.002765, Val MAE=0.029706, Val MedAE=0.016374, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:02.843 1: SolCast DEBUG&amp;gt; Epoche 100: Train MSE=0.001736, Val MSE=0.001509, Val MAE=0.026824, Val MedAE=0.022443, Bit_Fail=1&lt;br /&gt;
2026.01.01 18:04:07.181 1: SolCast DEBUG&amp;gt; Epoche 127: Train MSE=0.000623, Val MSE=0.001033, Val MAE=0.022203, Val MedAE=0.017074, Bit_Fail=1 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:04:07.341 1: SolCast DEBUG&amp;gt; Epoche 128: Train MSE=0.000611, Val MSE=0.001012, Val MAE=0.021994, Val MedAE=0.017013, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:07.519 1: SolCast DEBUG&amp;gt; Epoche 129: Train MSE=0.000599, Val MSE=0.000990, Val MAE=0.021783, Val MedAE=0.016793, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:07.994 1: SolCast DEBUG&amp;gt; Epoche 131: Train MSE=0.000577, Val MSE=0.000943, Val MAE=0.021456, Val MedAE=0.016655, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:08.185 1: SolCast DEBUG&amp;gt; Epoche 132: Train MSE=0.000566, Val MSE=0.000922, Val MAE=0.021240, Val MedAE=0.016463, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:08.344 1: SolCast DEBUG&amp;gt; Epoche 133: Train MSE=0.000554, Val MSE=0.000901, Val MAE=0.021025, Val MedAE=0.016355, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:08.508 1: SolCast DEBUG&amp;gt; Epoche 134: Train MSE=0.000543, Val MSE=0.000881, Val MAE=0.020809, Val MedAE=0.016328, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:08.684 1: SolCast DEBUG&amp;gt; Epoche 135: Train MSE=0.000532, Val MSE=0.000860, Val MAE=0.020593, Val MedAE=0.016227, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:08.840 1: SolCast DEBUG&amp;gt; Epoche 136: Train MSE=0.000521, Val MSE=0.000841, Val MAE=0.020381, Val MedAE=0.016031, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:08.989 1: SolCast DEBUG&amp;gt; Epoche 137: Train MSE=0.000511, Val MSE=0.000822, Val MAE=0.020175, Val MedAE=0.015652, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:09.144 1: SolCast DEBUG&amp;gt; Epoche 138: Train MSE=0.000501, Val MSE=0.000803, Val MAE=0.019972, Val MedAE=0.015495, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:09.297 1: SolCast DEBUG&amp;gt; Epoche 139: Train MSE=0.000492, Val MSE=0.000786, Val MAE=0.019773, Val MedAE=0.015409, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:09.458 1: SolCast DEBUG&amp;gt; Epoche 140: Train MSE=0.000481, Val MSE=0.000777, Val MAE=0.019495, Val MedAE=0.015158, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:09.615 1: SolCast DEBUG&amp;gt; Epoche 141: Train MSE=0.000473, Val MSE=0.000760, Val MAE=0.019325, Val MedAE=0.015145, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:09.767 1: SolCast DEBUG&amp;gt; Epoche 142: Train MSE=0.000465, Val MSE=0.000745, Val MAE=0.019163, Val MedAE=0.015044, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:09.919 1: SolCast DEBUG&amp;gt; Epoche 143: Train MSE=0.000457, Val MSE=0.000730, Val MAE=0.019008, Val MedAE=0.015017, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:10.080 1: SolCast DEBUG&amp;gt; Epoche 144: Train MSE=0.000449, Val MSE=0.000716, Val MAE=0.018857, Val MedAE=0.014983, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:10.245 1: SolCast DEBUG&amp;gt; Epoche 145: Train MSE=0.000442, Val MSE=0.000702, Val MAE=0.018714, Val MedAE=0.014883, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:10.400 1: SolCast DEBUG&amp;gt; Epoche 146: Train MSE=0.000436, Val MSE=0.000690, Val MAE=0.018579, Val MedAE=0.014777, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:10.705 1: SolCast DEBUG&amp;gt; Epoche 148: Train MSE=0.000424, Val MSE=0.000667, Val MAE=0.018328, Val MedAE=0.014732, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:10.858 1: SolCast DEBUG&amp;gt; Epoche 149: Train MSE=0.000418, Val MSE=0.000656, Val MAE=0.018213, Val MedAE=0.014659, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:11.447 1: SolCast DEBUG&amp;gt; Epoche 153: Train MSE=0.000398, Val MSE=0.000655, Val MAE=0.017918, Val MedAE=0.014430, Bit_Fail=0 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:04:11.597 1: SolCast DEBUG&amp;gt; Epoche 154: Train MSE=0.000394, Val MSE=0.000648, Val MAE=0.017836, Val MedAE=0.014356, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:11.780 1: SolCast DEBUG&amp;gt; Epoche 155: Train MSE=0.000390, Val MSE=0.000641, Val MAE=0.017757, Val MedAE=0.014209, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:11.968 1: SolCast DEBUG&amp;gt; Epoche 156: Train MSE=0.000386, Val MSE=0.000635, Val MAE=0.017685, Val MedAE=0.014026, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:12.119 1: SolCast DEBUG&amp;gt; Epoche 157: Train MSE=0.000383, Val MSE=0.000629, Val MAE=0.017617, Val MedAE=0.013986, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:15.889 1: SolCast DEBUG&amp;gt; Epoche 180: Train MSE=0.000338, Val MSE=0.000530, Val MAE=0.017079, Val MedAE=0.013927, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:19.269 1: SolCast DEBUG&amp;gt; Epoche 200: Train MSE=0.000338, Val MSE=0.000535, Val MAE=0.016673, Val MedAE=0.013893, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:04:35.878 1: SolCast DEBUG&amp;gt; Epoche 290: Train MSE=0.000288, Val MSE=0.000524, Val MAE=0.016388, Val MedAE=0.013535, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:36.582 1: SolCast DEBUG&amp;gt; Epoche 293: Train MSE=0.000287, Val MSE=0.000523, Val MAE=0.016367, Val MedAE=0.013507, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:37.370 1: SolCast DEBUG&amp;gt; Epoche 296: Train MSE=0.000287, Val MSE=0.000522, Val MAE=0.016353, Val MedAE=0.013413, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:38.343 1: SolCast DEBUG&amp;gt; Epoche 300: Train MSE=0.000287, Val MSE=0.000500, Val MAE=0.016520, Val MedAE=0.014059, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:04:53.153 1: SolCast DEBUG&amp;gt; Epoche 360: Train MSE=0.000276, Val MSE=0.000498, Val MAE=0.016213, Val MedAE=0.013363, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:05:03.452 1: SolCast DEBUG&amp;gt; Epoche 400: Train MSE=0.000276, Val MSE=0.000492, Val MAE=0.016416, Val MedAE=0.013627, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:05:29.137 1: SolCast DEBUG&amp;gt; Epoche 500: Train MSE=0.000276, Val MSE=0.000500, Val MAE=0.016208, Val MedAE=0.013216, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:05:51.013 1: SolCast DEBUG&amp;gt; Epoche 600: Train MSE=0.000276, Val MSE=0.000500, Val MAE=0.016319, Val MedAE=0.012971, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:06:14.772 1: SolCast DEBUG&amp;gt; Epoche 700: Train MSE=0.000276, Val MSE=0.000511, Val MAE=0.016383, Val MedAE=0.013241, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:06:36.483 1: SolCast DEBUG&amp;gt; Epoche 800: Train MSE=0.000276, Val MSE=0.000509, Val MAE=0.016792, Val MedAE=0.013049, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:06:52.867 1: SolCast DEBUG&amp;gt; Epoche 900: Train MSE=0.000276, Val MSE=0.000495, Val MAE=0.015972, Val MedAE=0.012938, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:06:52.877 1: SolCast DEBUG&amp;gt; Epoche 900: Train MSE=0.000242, Val MSE=0.000495, Val MAE=0.015972, Val MedAE=0.012938, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:07:09.391 1: SolCast DEBUG&amp;gt; Epoche 1000: Train MSE=0.000242, Val MSE=0.000493, Val MAE=0.016187, Val MedAE=0.013015, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:07:14.202 1: SolCast DEBUG&amp;gt; Epoche 1027: Train MSE=0.000237, Val MSE=0.000491, Val MAE=0.015971, Val MedAE=0.012928, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:07:18.001 1: SolCast DEBUG&amp;gt; Epoche 1050: Train MSE=0.000234, Val MSE=0.000486, Val MAE=0.015890, Val MedAE=0.012757, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:07:18.455 1: SolCast DEBUG&amp;gt; Epoche 1053: Train MSE=0.000234, Val MSE=0.000485, Val MAE=0.015881, Val MedAE=0.012678, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:07:25.760 1: SolCast DEBUG&amp;gt; Epoche 1100: Train MSE=0.000234, Val MSE=0.000480, Val MAE=0.015846, Val MedAE=0.012669, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:07:25.766 1: SolCast DEBUG&amp;gt; Epoche 1100: Train MSE=0.000233, Val MSE=0.000480, Val MAE=0.015846, Val MedAE=0.012669, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:07:42.102 1: SolCast DEBUG&amp;gt; Epoche 1200: Train MSE=0.000233, Val MSE=0.000484, Val MAE=0.016233, Val MedAE=0.012505, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:07:43.824 1: SolCast DEBUG&amp;gt; Epoche 1210: Train MSE=0.000227, Val MSE=0.000470, Val MAE=0.015552, Val MedAE=0.012390, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:07:57.828 1: SolCast DEBUG&amp;gt; Epoche 1300: Train MSE=0.000227, Val MSE=0.000520, Val MAE=0.017539, Val MedAE=0.013492, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:08:14.430 1: SolCast DEBUG&amp;gt; Epoche 1400: Train MSE=0.000227, Val MSE=0.000460, Val MAE=0.016046, Val MedAE=0.012304, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:08:16.132 1: SolCast DEBUG&amp;gt; Epoche 1410: Train MSE=0.000222, Val MSE=0.000452, Val MAE=0.015408, Val MedAE=0.011884, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:08:17.883 1: SolCast DEBUG&amp;gt; Epoche 1420: Train MSE=0.000220, Val MSE=0.000443, Val MAE=0.015258, Val MedAE=0.011811, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:08:29.901 1: SolCast DEBUG&amp;gt; Epoche 1490: Train MSE=0.000218, Val MSE=0.000439, Val MAE=0.014983, Val MedAE=0.011569, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:08:30.803 1: SolCast DEBUG&amp;gt; Epoche 1496: Train MSE=0.000218, Val MSE=0.000438, Val MAE=0.014960, Val MedAE=0.011509, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:08:31.440 1: SolCast DEBUG&amp;gt; Epoche 1500: Train MSE=0.000218, Val MSE=0.000439, Val MAE=0.015419, Val MedAE=0.011971, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:08:47.448 1: SolCast DEBUG&amp;gt; Epoche 1600: Train MSE=0.000218, Val MSE=0.000454, Val MAE=0.016309, Val MedAE=0.012168, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:08:50.500 1: SolCast DEBUG&amp;gt; Epoche 1620: Train MSE=0.000214, Val MSE=0.000431, Val MAE=0.014770, Val MedAE=0.011218, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:09:03.800 1: SolCast DEBUG&amp;gt; Epoche 1700: Train MSE=0.000214, Val MSE=0.000439, Val MAE=0.015947, Val MedAE=0.012095, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:09:12.275 1: SolCast DEBUG&amp;gt; Epoche 1755: Train MSE=0.000210, Val MSE=0.000414, Val MAE=0.014646, Val MedAE=0.011210, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:09:19.335 1: SolCast DEBUG&amp;gt; Epoche 1800: Train MSE=0.000210, Val MSE=0.000427, Val MAE=0.015787, Val MedAE=0.011912, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:09:36.229 1: SolCast DEBUG&amp;gt; Epoche 1900: Train MSE=0.000210, Val MSE=0.000417, Val MAE=0.015680, Val MedAE=0.011996, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:09:45.972 1: SolCast DEBUG&amp;gt; Epoche 1960: Train MSE=0.000204, Val MSE=0.000388, Val MAE=0.014589, Val MedAE=0.011116, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:09:51.969 1: SolCast DEBUG&amp;gt; Epoche 2000: Train MSE=0.000204, Val MSE=0.000404, Val MAE=0.015606, Val MedAE=0.012356, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:09:53.511 1: SolCast DEBUG&amp;gt; Epoche 2010: Train MSE=0.000202, Val MSE=0.000386, Val MAE=0.014313, Val MedAE=0.011006, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:09:55.063 1: SolCast DEBUG&amp;gt; Epoche 2020: Train MSE=0.000201, Val MSE=0.000383, Val MAE=0.014131, Val MedAE=0.010774, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:10:08.287 1: SolCast DEBUG&amp;gt; Epoche 2100: Train MSE=0.000201, Val MSE=0.000380, Val MAE=0.014528, Val MedAE=0.011353, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:10:24.098 1: SolCast DEBUG&amp;gt; Epoche 2200: Train MSE=0.000201, Val MSE=0.000370, Val MAE=0.013946, Val MedAE=0.010416, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:10:24.104 1: SolCast DEBUG&amp;gt; Epoche 2200: Train MSE=0.000197, Val MSE=0.000370, Val MAE=0.013946, Val MedAE=0.010416, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:10:39.646 1: SolCast DEBUG&amp;gt; Epoche 2300: Train MSE=0.000197, Val MSE=0.000374, Val MAE=0.014907, Val MedAE=0.011753, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:10:56.682 1: SolCast DEBUG&amp;gt; Epoche 2400: Train MSE=0.000197, Val MSE=0.000356, Val MAE=0.013705, Val MedAE=0.010006, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:10:56.693 1: SolCast DEBUG&amp;gt; Epoche 2400: Train MSE=0.000192, Val MSE=0.000356, Val MAE=0.013705, Val MedAE=0.010006, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:11:12.550 1: SolCast DEBUG&amp;gt; Epoche 2500: Train MSE=0.000192, Val MSE=0.000375, Val MAE=0.015257, Val MedAE=0.012743, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:11:15.676 1: SolCast DEBUG&amp;gt; Epoche 2520: Train MSE=0.000191, Val MSE=0.000355, Val MAE=0.013591, Val MedAE=0.009674, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:11:17.824 1: SolCast DEBUG&amp;gt; Epoche 2531: Train MSE=0.000190, Val MSE=0.000346, Val MAE=0.013480, Val MedAE=0.009639, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:11:28.987 1: SolCast DEBUG&amp;gt; Epoche 2600: Train MSE=0.000190, Val MSE=0.000339, Val MAE=0.013649, Val MedAE=0.010530, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:11:45.115 1: SolCast DEBUG&amp;gt; Epoche 2700: Train MSE=0.000190, Val MSE=0.000354, Val MAE=0.014651, Val MedAE=0.011877, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:12:01.075 1: SolCast DEBUG&amp;gt; Epoche 2790: Train MSE=0.000186, Val MSE=0.000341, Val MAE=0.013362, Val MedAE=0.009487, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:12:02.671 1: SolCast DEBUG&amp;gt; Epoche 2800: Train MSE=0.000186, Val MSE=0.000333, Val MAE=0.013606, Val MedAE=0.010687, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:12:18.422 1: SolCast DEBUG&amp;gt; Epoche 2900: Train MSE=0.000186, Val MSE=0.000335, Val MAE=0.013448, Val MedAE=0.010124, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:12:35.464 1: SolCast DEBUG&amp;gt; Epoche 3000: Train MSE=0.000186, Val MSE=0.000327, Val MAE=0.013352, Val MedAE=0.010017, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:12:56.411 1: SolCast DEBUG&amp;gt; Epoche 3100: Train MSE=0.000186, Val MSE=0.000333, Val MAE=0.013996, Val MedAE=0.011160, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:13:10.994 1: SolCast DEBUG&amp;gt; Epoche 3162: Train MSE=0.000181, Val MSE=0.000328, Val MAE=0.013113, Val MedAE=0.009469, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:13:18.736 1: SolCast DEBUG&amp;gt; Epoche 3200: Train MSE=0.000181, Val MSE=0.000320, Val MAE=0.013393, Val MedAE=0.010591, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:13:39.675 1: SolCast DEBUG&amp;gt; Epoche 3300: Train MSE=0.000181, Val MSE=0.000319, Val MAE=0.013325, Val MedAE=0.010389, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:14:00.271 1: SolCast DEBUG&amp;gt; Epoche 3400: Train MSE=0.000181, Val MSE=0.000325, Val MAE=0.014006, Val MedAE=0.011521, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:14:22.409 1: SolCast DEBUG&amp;gt; Epoche 3500: Train MSE=0.000181, Val MSE=0.000344, Val MAE=0.014666, Val MedAE=0.012138, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:14:38.101 1: SolCast DEBUG&amp;gt; Epoche 3580: Train MSE=0.000177, Val MSE=0.000319, Val MAE=0.012991, Val MedAE=0.009430, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:14:42.467 1: SolCast DEBUG&amp;gt; Epoche 3600: Train MSE=0.000177, Val MSE=0.000314, Val MAE=0.013079, Val MedAE=0.010056, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:15:03.838 1: SolCast DEBUG&amp;gt; Epoche 3700: Train MSE=0.000177, Val MSE=0.000333, Val MAE=0.014308, Val MedAE=0.011807, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:15:16.053 2: HUEBridge: http request failed: read from http://192.168.2.7:80 timed out&lt;br /&gt;
2026.01.01 18:15:30.476 1: SolCast DEBUG&amp;gt; Epoche 3800: Train MSE=0.000177, Val MSE=0.000321, Val MAE=0.013020, Val MedAE=0.009413, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:15:45.037 1: SolCast DEBUG&amp;gt; Epoche 3870: Train MSE=0.000174, Val MSE=0.000317, Val MAE=0.012911, Val MedAE=0.009292, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:15:52.131 1: SolCast DEBUG&amp;gt; Epoche 3900: Train MSE=0.000174, Val MSE=0.000312, Val MAE=0.013464, Val MedAE=0.010556, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:16:12.390 1: SolCast DEBUG&amp;gt; Epoche 4000: Train MSE=0.000174, Val MSE=0.000320, Val MAE=0.013974, Val MedAE=0.011455, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:16:29.091 1: SolCast DEBUG&amp;gt; Epoche 4100: Train MSE=0.000174, Val MSE=0.000312, Val MAE=0.013592, Val MedAE=0.010912, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:16:52.505 1: SolCast DEBUG&amp;gt; Epoche 4200: Train MSE=0.000174, Val MSE=0.000302, Val MAE=0.012962, Val MedAE=0.010156, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:17:16.099 1: SolCast DEBUG&amp;gt; Epoche 4300: Train MSE=0.000174, Val MSE=0.000303, Val MAE=0.013023, Val MedAE=0.010334, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:17:31.066 1: openMeteo - Open-Meteo API server response: start_SSL https://api.open-meteo.com:443 timed out&lt;br /&gt;
2026.01.01 18:17:38.285 1: SolCast DEBUG&amp;gt; Epoche 4400: Train MSE=0.000174, Val MSE=0.000302, Val MAE=0.013197, Val MedAE=0.010550, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:17:52.429 1: SolCast DEBUG&amp;gt; Epoche 4460: Train MSE=0.000170, Val MSE=0.000311, Val MAE=0.012837, Val MedAE=0.009137, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:17:58.628 1: SolCast DEBUG&amp;gt; Epoche 4490: Train MSE=0.000170, Val MSE=0.000305, Val MAE=0.012794, Val MedAE=0.009134, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:18:01.453 1: SolCast DEBUG&amp;gt; Epoche 4500: Train MSE=0.000170, Val MSE=0.000301, Val MAE=0.012898, Val MedAE=0.009802, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:18:23.799 1: SolCast DEBUG&amp;gt; Epoche 4600: Train MSE=0.000170, Val MSE=0.000298, Val MAE=0.012957, Val MedAE=0.010201, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:18:39.811 1: SolCast DEBUG&amp;gt; Epoche 4700: Train MSE=0.000170, Val MSE=0.000301, Val MAE=0.013527, Val MedAE=0.011413, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:18:56.354 1: SolCast DEBUG&amp;gt; Epoche 4800: Train MSE=0.000170, Val MSE=0.000298, Val MAE=0.013255, Val MedAE=0.011018, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:19:12.392 1: SolCast DEBUG&amp;gt; Epoche 4900: Train MSE=0.000170, Val MSE=0.000295, Val MAE=0.013216, Val MedAE=0.010940, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:19:27.987 1: SolCast DEBUG&amp;gt; Epoche 5000: Train MSE=0.000170, Val MSE=0.000293, Val MAE=0.013073, Val MedAE=0.010728, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:19:32.327 1: SolCast DEBUG&amp;gt; Epoche 5030: Train MSE=0.000167, Val MSE=0.000297, Val MAE=0.012698, Val MedAE=0.009102, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:19:43.670 1: SolCast DEBUG&amp;gt; Epoche 5100: Train MSE=0.000167, Val MSE=0.000298, Val MAE=0.013300, Val MedAE=0.010884, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:19:59.190 1: SolCast DEBUG&amp;gt; Epoche 5200: Train MSE=0.000167, Val MSE=0.000294, Val MAE=0.013167, Val MedAE=0.010790, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:20:10.606 1: SolCast DEBUG&amp;gt; Epoche 5262: Train MSE=0.000166, Val MSE=0.000295, Val MAE=0.012677, Val MedAE=0.009089, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:20:16.409 1: SolCast DEBUG&amp;gt; Epoche 5300: Train MSE=0.000166, Val MSE=0.000292, Val MAE=0.013247, Val MedAE=0.011177, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:20:34.708 1: SolCast DEBUG&amp;gt; Epoche 5400: Train MSE=0.000166, Val MSE=0.000291, Val MAE=0.012964, Val MedAE=0.010392, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:20:57.206 1: SolCast DEBUG&amp;gt; Epoche 5500: Train MSE=0.000166, Val MSE=0.000288, Val MAE=0.012996, Val MedAE=0.010552, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:21:21.536 1: SolCast DEBUG&amp;gt; Epoche 5600: Train MSE=0.000166, Val MSE=0.000286, Val MAE=0.012927, Val MedAE=0.010610, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:21:43.826 1: SolCast DEBUG&amp;gt; Epoche 5700: Train MSE=0.000166, Val MSE=0.000284, Val MAE=0.012811, Val MedAE=0.010111, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:21:46.073 1: SolCast DEBUG&amp;gt; Epoche 5710: Train MSE=0.000164, Val MSE=0.000292, Val MAE=0.012617, Val MedAE=0.009052, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:22:05.636 1: SolCast DEBUG&amp;gt; Epoche 5800: Train MSE=0.000164, Val MSE=0.000311, Val MAE=0.013979, Val MedAE=0.012142, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:22:28.019 1: SolCast DEBUG&amp;gt; Epoche 5900: Train MSE=0.000164, Val MSE=0.000284, Val MAE=0.012679, Val MedAE=0.009654, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:22:44.531 1: SolCast DEBUG&amp;gt; Epoche 6000: Train MSE=0.000164, Val MSE=0.000333, Val MAE=0.014735, Val MedAE=0.013016, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:23:00.239 1: SolCast DEBUG&amp;gt; Epoche 6100: Train MSE=0.000164, Val MSE=0.000286, Val MAE=0.012652, Val MedAE=0.009522, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:23:16.145 1: SolCast DEBUG&amp;gt; Epoche 6200: Train MSE=0.000164, Val MSE=0.000283, Val MAE=0.012623, Val MedAE=0.009526, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:23:31.970 1: SolCast DEBUG&amp;gt; Epoche 6300: Train MSE=0.000164, Val MSE=0.000294, Val MAE=0.013520, Val MedAE=0.011589, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:23:48.995 1: SolCast DEBUG&amp;gt; Epoche 6400: Train MSE=0.000164, Val MSE=0.000290, Val MAE=0.013238, Val MedAE=0.011187, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:24:04.958 1: SolCast DEBUG&amp;gt; Epoche 6500: Train MSE=0.000164, Val MSE=0.000283, Val MAE=0.013087, Val MedAE=0.011112, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:24:20.473 1: SolCast DEBUG&amp;gt; Epoche 6600: Train MSE=0.000164, Val MSE=0.000291, Val MAE=0.012657, Val MedAE=0.009198, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:24:35.890 1: SolCast DEBUG&amp;gt; Epoche 6700: Train MSE=0.000164, Val MSE=0.000290, Val MAE=0.013459, Val MedAE=0.011749, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:24:52.891 1: SolCast DEBUG&amp;gt; Epoche 6800: Train MSE=0.000164, Val MSE=0.000289, Val MAE=0.013364, Val MedAE=0.011509, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:25:08.802 1: SolCast DEBUG&amp;gt; Epoche 6900: Train MSE=0.000164, Val MSE=0.000283, Val MAE=0.013144, Val MedAE=0.011185, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:25:24.371 1: SolCast DEBUG&amp;gt; Epoche 7000: Train MSE=0.000164, Val MSE=0.000278, Val MAE=0.012650, Val MedAE=0.009934, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:25:39.968 1: SolCast DEBUG&amp;gt; Epoche 7100: Train MSE=0.000164, Val MSE=0.000320, Val MAE=0.014405, Val MedAE=0.012857, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:25:56.650 1: SolCast DEBUG&amp;gt; Epoche 7200: Train MSE=0.000164, Val MSE=0.000281, Val MAE=0.013030, Val MedAE=0.011100, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:26:12.530 1: SolCast DEBUG&amp;gt; Epoche 7300: Train MSE=0.000164, Val MSE=0.000277, Val MAE=0.012556, Val MedAE=0.009580, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:26:28.387 1: SolCast DEBUG&amp;gt; Epoche 7400: Train MSE=0.000164, Val MSE=0.000275, Val MAE=0.012574, Val MedAE=0.009786, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:26:44.426 1: SolCast DEBUG&amp;gt; Epoche 7500: Train MSE=0.000164, Val MSE=0.000282, Val MAE=0.013197, Val MedAE=0.011348, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:27:00.108 1: SolCast DEBUG&amp;gt; Epoche 7600: Train MSE=0.000164, Val MSE=0.000279, Val MAE=0.012521, Val MedAE=0.009349, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:27:17.631 1: SolCast DEBUG&amp;gt; Epoche 7700: Train MSE=0.000164, Val MSE=0.000334, Val MAE=0.014836, Val MedAE=0.013130, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:27:19.201 1: SolCast DEBUG&amp;gt; Early stopping bei Epoche 7710 (no improvement since 2000 epochs)&lt;br /&gt;
2026.01.01 18:27:19.203 1: === Snapshot-Statistik ===&lt;br /&gt;
2026.01.01 18:27:19.206 1: Metric-Improvement Snapshots: 59 (letzte Epoche: 5710)&lt;br /&gt;
2026.01.01 18:27:19.208 1: Bit-Improvement Snapshots:    3 (letzte Epoche: 153)&lt;br /&gt;
2026.01.01 18:27:19.211 1: Bit-Tradeoff Snapshots:       0 (letzte Epoche: 0)&lt;br /&gt;
2026.01.01 18:27:19.222 1: SolCast DEBUG&amp;gt; Best Snapshot reloaded from Epoche 5710: Train MSE=0.000164, Val MSE=0.000292, Val MAE=0.012617, Val MedAE=0.009052, Bit_Fail=0,&lt;br /&gt;
2026.01.01 18:27:19.225 1: SolCast DEBUG&amp;gt; Run Validation Test with 20% of Input data ...&lt;br /&gt;
2026.01.01 18:27:19.269 1: SolCast DEBUG&amp;gt; Validation finished - Best Training MSE=0.000164, Validation MSE=0.000292, Validation Bit_Fail=0&lt;br /&gt;
2026.01.01 18:27:19.272 1: SolCast DEBUG&amp;gt; Retrain check -&amp;gt; &lt;br /&gt;
-- In Normalization Space: -- &lt;br /&gt;
Train MSE=0.000164 &lt;br /&gt;
Val MSE=0.000292 &lt;br /&gt;
Val Mean=0.0003006352 &lt;br /&gt;
VAL/TRAIN MSE Ratio=1.778317 (limit=2.5) &lt;br /&gt;
Diff=0.000128 (limit=0.005) &lt;br /&gt;
ValStd=0.0000223852 (limit=7.51588070934039e-05) &lt;br /&gt;
-- At Original Scale: -- &lt;br /&gt;
MAE=207.818584965433 &lt;br /&gt;
RMSE/MAE=1.3545 (limit=1.5) &lt;br /&gt;
Slope=0.930345 (limit=0.7 .. 1.3) &lt;br /&gt;
Bias=-1.81 (limit=+-103.909292482717) &lt;br /&gt;
R2=0.896675647742538 &lt;br /&gt;
P95=565.7317 (limit=831.274339861732) &lt;br /&gt;
P99=813.5925 (limit=1662.54867972346) &lt;br /&gt;
-- Robustness Indicators: -- &lt;br /&gt;
RMSE relative=60 (limit=20) &lt;br /&gt;
BitFail=0 (limit=5) &lt;br /&gt;
BitFailRate=0.0000 (limit=0.1) &lt;br /&gt;
-&amp;gt; Retrain&lt;br /&gt;
2026.01.01 18:27:19.280 1: SolCast DEBUG&amp;gt; Retry attempt 1 with Seed=16816002&lt;br /&gt;
2026.01.01 18:27:19.287 1: SolCast DEBUG&amp;gt; AI FANN Training started with Params:&lt;br /&gt;
num input datasets=7314, &lt;br /&gt;
training algo=FANN_TRAIN_INCREMENTAL, &lt;br /&gt;
output AF=LINEAR, &lt;br /&gt;
hidden AF=SIGMOID, &lt;br /&gt;
hidden Neurons=80,40,20, &lt;br /&gt;
hidden steepness=0.9, &lt;br /&gt;
Epoches=15000, &lt;br /&gt;
mse_error=0.001, &lt;br /&gt;
learning rate=0.00500, &lt;br /&gt;
learning momentum=0.7, &lt;br /&gt;
Data sharing=split after shuffle of training data and use AI internal shuffle (Train=5851, Test=1462), &lt;br /&gt;
Data shuffle=2 (period=10)&lt;br /&gt;
2026.01.01 18:27:19.448 1: SolCast DEBUG&amp;gt; Epoche 1: Train MSE=0.002204, Val MSE=0.002840, Val MAE=0.031967, Val MedAE=0.027950, Bit_Fail=2 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:27:27.760 1: SolCast DEBUG&amp;gt; Epoche 55: Train MSE=0.001883, Val MSE=0.002825, Val MAE=0.030076, Val MedAE=0.017712, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:27.909 1: SolCast DEBUG&amp;gt; Epoche 56: Train MSE=0.001848, Val MSE=0.002787, Val MAE=0.029877, Val MedAE=0.017254, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:28.093 1: SolCast DEBUG&amp;gt; Epoche 57: Train MSE=0.001806, Val MSE=0.002742, Val MAE=0.029648, Val MedAE=0.016877, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:28.250 1: SolCast DEBUG&amp;gt; Epoche 58: Train MSE=0.001759, Val MSE=0.002690, Val MAE=0.029392, Val MedAE=0.016720, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:28.410 1: SolCast DEBUG&amp;gt; Epoche 59: Train MSE=0.001704, Val MSE=0.002632, Val MAE=0.029109, Val MedAE=0.016686, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:34.691 1: SolCast DEBUG&amp;gt; Epoche 100: Train MSE=0.001704, Val MSE=0.001681, Val MAE=0.026853, Val MedAE=0.019229, Bit_Fail=1&lt;br /&gt;
2026.01.01 18:27:39.980 1: SolCast DEBUG&amp;gt; Epoche 133: Train MSE=0.000733, Val MSE=0.001267, Val MAE=0.023793, Val MedAE=0.017436, Bit_Fail=1 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:27:40.226 1: SolCast DEBUG&amp;gt; Epoche 134: Train MSE=0.000722, Val MSE=0.001247, Val MAE=0.023624, Val MedAE=0.017294, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:40.470 1: SolCast DEBUG&amp;gt; Epoche 135: Train MSE=0.000710, Val MSE=0.001225, Val MAE=0.023450, Val MedAE=0.017111, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:40.655 1: SolCast DEBUG&amp;gt; Epoche 136: Train MSE=0.000698, Val MSE=0.001204, Val MAE=0.023271, Val MedAE=0.017081, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:40.821 1: SolCast DEBUG&amp;gt; Epoche 137: Train MSE=0.000686, Val MSE=0.001182, Val MAE=0.023085, Val MedAE=0.017060, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:40.979 1: SolCast DEBUG&amp;gt; Epoche 138: Train MSE=0.000674, Val MSE=0.001160, Val MAE=0.022895, Val MedAE=0.016883, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:41.140 1: SolCast DEBUG&amp;gt; Epoche 139: Train MSE=0.000661, Val MSE=0.001138, Val MAE=0.022701, Val MedAE=0.016711, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:41.929 1: SolCast DEBUG&amp;gt; Epoche 144: Train MSE=0.000598, Val MSE=0.000999, Val MAE=0.021734, Val MedAE=0.016540, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:42.090 1: SolCast DEBUG&amp;gt; Epoche 145: Train MSE=0.000586, Val MSE=0.000978, Val MAE=0.021522, Val MedAE=0.016349, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:42.280 1: SolCast DEBUG&amp;gt; Epoche 146: Train MSE=0.000574, Val MSE=0.000958, Val MAE=0.021306, Val MedAE=0.016107, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:42.459 1: SolCast DEBUG&amp;gt; Epoche 147: Train MSE=0.000562, Val MSE=0.000937, Val MAE=0.021088, Val MedAE=0.015901, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:42.613 1: SolCast DEBUG&amp;gt; Epoche 148: Train MSE=0.000550, Val MSE=0.000918, Val MAE=0.020870, Val MedAE=0.015669, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:42.760 1: SolCast DEBUG&amp;gt; Epoche 149: Train MSE=0.000539, Val MSE=0.000898, Val MAE=0.020654, Val MedAE=0.015555, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:43.090 1: SolCast DEBUG&amp;gt; Epoche 151: Train MSE=0.000519, Val MSE=0.000853, Val MAE=0.020213, Val MedAE=0.015324, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:43.274 1: SolCast DEBUG&amp;gt; Epoche 152: Train MSE=0.000508, Val MSE=0.000834, Val MAE=0.019989, Val MedAE=0.015218, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:43.427 1: SolCast DEBUG&amp;gt; Epoche 153: Train MSE=0.000498, Val MSE=0.000815, Val MAE=0.019775, Val MedAE=0.015098, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:43.588 1: SolCast DEBUG&amp;gt; Epoche 154: Train MSE=0.000489, Val MSE=0.000798, Val MAE=0.019572, Val MedAE=0.015089, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:43.765 1: SolCast DEBUG&amp;gt; Epoche 155: Train MSE=0.000480, Val MSE=0.000781, Val MAE=0.019377, Val MedAE=0.014943, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:43.922 1: SolCast DEBUG&amp;gt; Epoche 156: Train MSE=0.000471, Val MSE=0.000765, Val MAE=0.019192, Val MedAE=0.014814, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:44.099 1: SolCast DEBUG&amp;gt; Epoche 157: Train MSE=0.000463, Val MSE=0.000750, Val MAE=0.019017, Val MedAE=0.014635, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:44.451 1: SolCast DEBUG&amp;gt; Epoche 159: Train MSE=0.000448, Val MSE=0.000722, Val MAE=0.018698, Val MedAE=0.014553, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:45.216 1: SolCast DEBUG&amp;gt; Epoche 164: Train MSE=0.000417, Val MSE=0.000649, Val MAE=0.018205, Val MedAE=0.014516, Bit_Fail=0 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:27:45.399 1: SolCast DEBUG&amp;gt; Epoche 165: Train MSE=0.000412, Val MSE=0.000640, Val MAE=0.018099, Val MedAE=0.014421, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:45.558 1: SolCast DEBUG&amp;gt; Epoche 166: Train MSE=0.000407, Val MSE=0.000632, Val MAE=0.017999, Val MedAE=0.014286, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:45.726 1: SolCast DEBUG&amp;gt; Epoche 167: Train MSE=0.000402, Val MSE=0.000624, Val MAE=0.017906, Val MedAE=0.014177, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:45.885 1: SolCast DEBUG&amp;gt; Epoche 168: Train MSE=0.000398, Val MSE=0.000617, Val MAE=0.017820, Val MedAE=0.014094, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:46.051 1: SolCast DEBUG&amp;gt; Epoche 169: Train MSE=0.000394, Val MSE=0.000610, Val MAE=0.017740, Val MedAE=0.014051, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:50.636 1: SolCast DEBUG&amp;gt; Epoche 200: Train MSE=0.000394, Val MSE=0.000539, Val MAE=0.016987, Val MedAE=0.013961, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:27:50.644 1: SolCast DEBUG&amp;gt; Epoche 200: Train MSE=0.000340, Val MSE=0.000539, Val MAE=0.016987, Val MedAE=0.013961, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:51.095 1: SolCast DEBUG&amp;gt; Epoche 203: Train MSE=0.000338, Val MSE=0.000538, Val MAE=0.016940, Val MedAE=0.013888, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:55.790 1: SolCast DEBUG&amp;gt; Epoche 233: Train MSE=0.000321, Val MSE=0.000535, Val MAE=0.016852, Val MedAE=0.013875, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:03.726 1: SolCast DEBUG&amp;gt; Epoche 281: Train MSE=0.000308, Val MSE=0.000524, Val MAE=0.016435, Val MedAE=0.013831, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:04.363 1: SolCast DEBUG&amp;gt; Epoche 285: Train MSE=0.000307, Val MSE=0.000523, Val MAE=0.016426, Val MedAE=0.013765, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:06.794 1: SolCast DEBUG&amp;gt; Epoche 300: Train MSE=0.000307, Val MSE=0.000550, Val MAE=0.017907, Val MedAE=0.015240, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:28:08.309 1: SolCast DEBUG&amp;gt; Epoche 310: Train MSE=0.000306, Val MSE=0.000520, Val MAE=0.016274, Val MedAE=0.013632, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:08.614 1: SolCast DEBUG&amp;gt; Epoche 312: Train MSE=0.000305, Val MSE=0.000519, Val MAE=0.016257, Val MedAE=0.013585, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:09.360 1: SolCast DEBUG&amp;gt; Epoche 317: Train MSE=0.000304, Val MSE=0.000518, Val MAE=0.016235, Val MedAE=0.013539, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:18.741 1: SolCast DEBUG&amp;gt; Epoche 370: Train MSE=0.000293, Val MSE=0.000514, Val MAE=0.016166, Val MedAE=0.013205, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:23.398 1: SolCast DEBUG&amp;gt; Epoche 400: Train MSE=0.000293, Val MSE=0.000498, Val MAE=0.016166, Val MedAE=0.013530, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:28:27.156 1: SolCast DEBUG&amp;gt; Epoche 420: Train MSE=0.000286, Val MSE=0.000497, Val MAE=0.015836, Val MedAE=0.012658, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:27.956 1: SolCast DEBUG&amp;gt; Epoche 424: Train MSE=0.000286, Val MSE=0.000496, Val MAE=0.015803, Val MedAE=0.012630, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:28.927 1: SolCast DEBUG&amp;gt; Epoche 429: Train MSE=0.000285, Val MSE=0.000495, Val MAE=0.015779, Val MedAE=0.012568, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:37.533 1: SolCast DEBUG&amp;gt; Epoche 470: Train MSE=0.000278, Val MSE=0.000490, Val MAE=0.015754, Val MedAE=0.012467, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:44.668 1: SolCast DEBUG&amp;gt; Epoche 500: Train MSE=0.000278, Val MSE=0.000512, Val MAE=0.015775, Val MedAE=0.011966, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:28:49.391 1: SolCast DEBUG&amp;gt; Epoche 520: Train MSE=0.000270, Val MSE=0.000477, Val MAE=0.015651, Val MedAE=0.012339, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:53.585 1: SolCast DEBUG&amp;gt; Epoche 539: Train MSE=0.000270, Val MSE=0.000475, Val MAE=0.015648, Val MedAE=0.012191, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:29:05.842 1: SolCast DEBUG&amp;gt; Epoche 590: Train MSE=0.000265, Val MSE=0.000474, Val MAE=0.015526, Val MedAE=0.012056, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:29:08.065 1: SolCast DEBUG&amp;gt; Epoche 600: Train MSE=0.000265, Val MSE=0.000468, Val MAE=0.015894, Val MedAE=0.012751, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:29:28.474 1: SolCast DEBUG&amp;gt; Epoche 690: Train MSE=0.000256, Val MSE=0.000470, Val MAE=0.015276, Val MedAE=0.011856, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:29:30.383 1: SolCast DEBUG&amp;gt; Epoche 699: Train MSE=0.000255, Val MSE=0.000467, Val MAE=0.015250, Val MedAE=0.011836, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:29:30.639 1: SolCast DEBUG&amp;gt; Epoche 700: Train MSE=0.000255, Val MSE=0.000478, Val MAE=0.016548, Val MedAE=0.013898, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:29:52.830 1: SolCast DEBUG&amp;gt; Epoche 800: Train MSE=0.000255, Val MSE=0.000465, Val MAE=0.016306, Val MedAE=0.013391, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:30:04.934 1: SolCast DEBUG&amp;gt; Epoche 850: Train MSE=0.000244, Val MSE=0.000461, Val MAE=0.015129, Val MedAE=0.011815, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:30:17.777 1: SolCast DEBUG&amp;gt; Epoche 900: Train MSE=0.000244, Val MSE=0.000448, Val MAE=0.015585, Val MedAE=0.012575, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:30:40.850 1: SolCast DEBUG&amp;gt; Epoche 1000: Train MSE=0.000244, Val MSE=0.000450, Val MAE=0.015295, Val MedAE=0.012324, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:30:56.457 1: SolCast DEBUG&amp;gt; Epoche 1100: Train MSE=0.000244, Val MSE=0.000443, Val MAE=0.015695, Val MedAE=0.012932, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:31:07.100 1: SolCast DEBUG&amp;gt; Epoche 1160: Train MSE=0.000229, Val MSE=0.000432, Val MAE=0.014957, Val MedAE=0.011802, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:31:13.278 1: SolCast DEBUG&amp;gt; Epoche 1200: Train MSE=0.000229, Val MSE=0.000439, Val MAE=0.015822, Val MedAE=0.012868, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:31:29.055 1: SolCast DEBUG&amp;gt; Epoche 1300: Train MSE=0.000229, Val MSE=0.000435, Val MAE=0.015613, Val MedAE=0.012747, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:31:43.689 1: SolCast DEBUG&amp;gt; Epoche 1390: Train MSE=0.000219, Val MSE=0.000426, Val MAE=0.014936, Val MedAE=0.011470, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:31:45.625 1: SolCast DEBUG&amp;gt; Epoche 1400: Train MSE=0.000219, Val MSE=0.000414, Val MAE=0.014586, Val MedAE=0.011035, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:31:45.635 1: SolCast DEBUG&amp;gt; Epoche 1400: Train MSE=0.000218, Val MSE=0.000414, Val MAE=0.014586, Val MedAE=0.011035, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:32:02.161 1: SolCast DEBUG&amp;gt; Epoche 1500: Train MSE=0.000218, Val MSE=0.000449, Val MAE=0.016432, Val MedAE=0.013464, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:32:18.086 1: SolCast DEBUG&amp;gt; Epoche 1600: Train MSE=0.000218, Val MSE=0.000403, Val MAE=0.014934, Val MedAE=0.011695, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:32:32.114 1: SolCast DEBUG&amp;gt; Epoche 1690: Train MSE=0.000209, Val MSE=0.000404, Val MAE=0.014320, Val MedAE=0.010320, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:32:33.832 1: SolCast DEBUG&amp;gt; Epoche 1700: Train MSE=0.000209, Val MSE=0.000428, Val MAE=0.016037, Val MedAE=0.012994, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:32:49.865 1: SolCast DEBUG&amp;gt; Epoche 1800: Train MSE=0.000209, Val MSE=0.000410, Val MAE=0.015653, Val MedAE=0.012577, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:33:02.182 1: SolCast DEBUG&amp;gt; Epoche 1870: Train MSE=0.000205, Val MSE=0.000383, Val MAE=0.014067, Val MedAE=0.010133, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:33:06.890 1: SolCast DEBUG&amp;gt; Epoche 1900: Train MSE=0.000205, Val MSE=0.000376, Val MAE=0.014446, Val MedAE=0.011115, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:33:22.858 1: SolCast DEBUG&amp;gt; Epoche 2000: Train MSE=0.000205, Val MSE=0.000368, Val MAE=0.014258, Val MedAE=0.010752, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:33:38.578 1: SolCast DEBUG&amp;gt; Epoche 2100: Train MSE=0.000205, Val MSE=0.000440, Val MAE=0.016680, Val MedAE=0.014515, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:33:41.611 1: SolCast DEBUG&amp;gt; Epoche 2120: Train MSE=0.000198, Val MSE=0.000367, Val MAE=0.013801, Val MedAE=0.009661, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:33:54.354 1: SolCast DEBUG&amp;gt; Epoche 2200: Train MSE=0.000198, Val MSE=0.000417, Val MAE=0.016140, Val MedAE=0.013713, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:34:11.686 1: SolCast DEBUG&amp;gt; Epoche 2300: Train MSE=0.000198, Val MSE=0.000362, Val MAE=0.014348, Val MedAE=0.010921, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:34:18.148 1: SolCast DEBUG&amp;gt; Epoche 2340: Train MSE=0.000195, Val MSE=0.000356, Val MAE=0.013592, Val MedAE=0.009300, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:34:27.489 1: SolCast DEBUG&amp;gt; Epoche 2400: Train MSE=0.000195, Val MSE=0.000355, Val MAE=0.014051, Val MedAE=0.010411, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:34:43.305 1: SolCast DEBUG&amp;gt; Epoche 2500: Train MSE=0.000195, Val MSE=0.000349, Val MAE=0.013577, Val MedAE=0.009666, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:34:58.973 1: SolCast DEBUG&amp;gt; Epoche 2600: Train MSE=0.000195, Val MSE=0.000377, Val MAE=0.015170, Val MedAE=0.012456, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:35:15.415 1: SolCast DEBUG&amp;gt; Epoche 2700: Train MSE=0.000195, Val MSE=0.000340, Val MAE=0.013970, Val MedAE=0.010876, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:35:32.017 1: SolCast DEBUG&amp;gt; Epoche 2800: Train MSE=0.000195, Val MSE=0.000382, Val MAE=0.015341, Val MedAE=0.012854, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:35:47.827 1: SolCast DEBUG&amp;gt; Epoche 2900: Train MSE=0.000195, Val MSE=0.000328, Val MAE=0.013411, Val MedAE=0.009790, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:35:52.375 1: SolCast DEBUG&amp;gt; Epoche 2931: Train MSE=0.000186, Val MSE=0.000331, Val MAE=0.013276, Val MedAE=0.009297, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:36:04.885 1: SolCast DEBUG&amp;gt; Epoche 3000: Train MSE=0.000186, Val MSE=0.000333, Val MAE=0.013785, Val MedAE=0.010478, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:36:20.725 1: SolCast DEBUG&amp;gt; Epoche 3100: Train MSE=0.000186, Val MSE=0.000329, Val MAE=0.013228, Val MedAE=0.009287, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:36:20.735 1: SolCast DEBUG&amp;gt; Epoche 3100: Train MSE=0.000184, Val MSE=0.000329, Val MAE=0.013228, Val MedAE=0.009287, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:36:34.489 1: SolCast DEBUG&amp;gt; Epoche 3180: Train MSE=0.000182, Val MSE=0.000327, Val MAE=0.013125, Val MedAE=0.008939, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:36:38.029 1: SolCast DEBUG&amp;gt; Epoche 3200: Train MSE=0.000182, Val MSE=0.000320, Val MAE=0.013228, Val MedAE=0.009632, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:36:45.842 1: SolCast DEBUG&amp;gt; Epoche 3250: Train MSE=0.000183, Val MSE=0.000323, Val MAE=0.013096, Val MedAE=0.008886, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:36:53.303 1: SolCast DEBUG&amp;gt; Epoche 3300: Train MSE=0.000183, Val MSE=0.000320, Val MAE=0.013318, Val MedAE=0.009760, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:37:09.545 1: SolCast DEBUG&amp;gt; Epoche 3400: Train MSE=0.000183, Val MSE=0.000327, Val MAE=0.013922, Val MedAE=0.011272, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:37:24.189 1: SolCast DEBUG&amp;gt; Epoche 3490: Train MSE=0.000180, Val MSE=0.000319, Val MAE=0.013041, Val MedAE=0.008820, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:37:25.723 1: SolCast DEBUG&amp;gt; Epoche 3500: Train MSE=0.000180, Val MSE=0.000323, Val MAE=0.013588, Val MedAE=0.010386, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:37:47.590 1: SolCast DEBUG&amp;gt; Epoche 3600: Train MSE=0.000180, Val MSE=0.000323, Val MAE=0.013730, Val MedAE=0.010947, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:37:53.258 1: SolCast DEBUG&amp;gt; Epoche 3630: Train MSE=0.000178, Val MSE=0.000318, Val MAE=0.012948, Val MedAE=0.008677, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:38:09.034 1: SolCast DEBUG&amp;gt; Epoche 3700: Train MSE=0.000178, Val MSE=0.000312, Val MAE=0.013378, Val MedAE=0.010497, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:38:30.192 1: SolCast DEBUG&amp;gt; Epoche 3800: Train MSE=0.000178, Val MSE=0.000312, Val MAE=0.013379, Val MedAE=0.010674, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:38:52.224 1: SolCast DEBUG&amp;gt; Epoche 3900: Train MSE=0.000178, Val MSE=0.000318, Val MAE=0.012933, Val MedAE=0.008471, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:39:13.603 1: SolCast DEBUG&amp;gt; Epoche 4000: Train MSE=0.000178, Val MSE=0.000306, Val MAE=0.013228, Val MedAE=0.010395, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:39:34.047 1: SolCast DEBUG&amp;gt; Epoche 4100: Train MSE=0.000178, Val MSE=0.000318, Val MAE=0.013793, Val MedAE=0.011333, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:39:54.812 1: SolCast DEBUG&amp;gt; Epoche 4200: Train MSE=0.000178, Val MSE=0.000309, Val MAE=0.013388, Val MedAE=0.010831, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:40:02.202 1: SolCast DEBUG&amp;gt; Epoche 4230: Train MSE=0.000175, Val MSE=0.000309, Val MAE=0.012845, Val MedAE=0.008584, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:40:16.021 1: SolCast DEBUG&amp;gt; Epoche 4300: Train MSE=0.000175, Val MSE=0.000303, Val MAE=0.013012, Val MedAE=0.009822, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:40:34.355 1: SolCast DEBUG&amp;gt; Epoche 4400: Train MSE=0.000175, Val MSE=0.000310, Val MAE=0.012884, Val MedAE=0.008766, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:40:57.218 1: SolCast DEBUG&amp;gt; Epoche 4500: Train MSE=0.000175, Val MSE=0.000302, Val MAE=0.013128, Val MedAE=0.010345, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:41:22.220 1: SolCast DEBUG&amp;gt; Epoche 4600: Train MSE=0.000175, Val MSE=0.000302, Val MAE=0.013191, Val MedAE=0.010385, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:41:43.986 1: SolCast DEBUG&amp;gt; Epoche 4700: Train MSE=0.000175, Val MSE=0.000301, Val MAE=0.013269, Val MedAE=0.010709, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:42:05.591 1: SolCast DEBUG&amp;gt; Epoche 4800: Train MSE=0.000175, Val MSE=0.000327, Val MAE=0.012984, Val MedAE=0.008358, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:42:28.817 1: SolCast DEBUG&amp;gt; Epoche 4900: Train MSE=0.000175, Val MSE=0.000300, Val MAE=0.013196, Val MedAE=0.010534, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:42:51.092 1: SolCast DEBUG&amp;gt; Epoche 5000: Train MSE=0.000175, Val MSE=0.000298, Val MAE=0.013025, Val MedAE=0.010142, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:43:13.597 1: SolCast DEBUG&amp;gt; Epoche 5100: Train MSE=0.000175, Val MSE=0.000296, Val MAE=0.012895, Val MedAE=0.009981, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:43:36.900 1: SolCast DEBUG&amp;gt; Epoche 5200: Train MSE=0.000175, Val MSE=0.000298, Val MAE=0.012955, Val MedAE=0.009983, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:43:58.243 1: SolCast DEBUG&amp;gt; Epoche 5300: Train MSE=0.000175, Val MSE=0.000305, Val MAE=0.013474, Val MedAE=0.010999, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:44:20.399 1: SolCast DEBUG&amp;gt; Epoche 5400: Train MSE=0.000175, Val MSE=0.000296, Val MAE=0.012941, Val MedAE=0.009892, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:44:37.326 1: SolCast DEBUG&amp;gt; Epoche 5500: Train MSE=0.000175, Val MSE=0.000301, Val MAE=0.013345, Val MedAE=0.010900, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:44:53.049 1: SolCast DEBUG&amp;gt; Epoche 5600: Train MSE=0.000175, Val MSE=0.000297, Val MAE=0.012997, Val MedAE=0.010176, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:45:10.274 1: SolCast DEBUG&amp;gt; Epoche 5700: Train MSE=0.000175, Val MSE=0.000303, Val MAE=0.013484, Val MedAE=0.011050, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:45:27.329 1: SolCast DEBUG&amp;gt; Epoche 5800: Train MSE=0.000175, Val MSE=0.000300, Val MAE=0.013419, Val MedAE=0.011095, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:45:42.673 1: SolCast DEBUG&amp;gt; Epoche 5900: Train MSE=0.000175, Val MSE=0.000295, Val MAE=0.013058, Val MedAE=0.010464, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:45:59.007 1: SolCast DEBUG&amp;gt; Epoche 6000: Train MSE=0.000175, Val MSE=0.000299, Val MAE=0.012793, Val MedAE=0.009330, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:46:14.775 1: SolCast DEBUG&amp;gt; Epoche 6100: Train MSE=0.000175, Val MSE=0.000294, Val MAE=0.013040, Val MedAE=0.010396, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:46:29.912 1: SolCast DEBUG&amp;gt; Epoche 6200: Train MSE=0.000175, Val MSE=0.000305, Val MAE=0.013656, Val MedAE=0.011383, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:46:34.543 1: SolCast DEBUG&amp;gt; Early stopping bei Epoche 6230 (no improvement since 2000 epochs)&lt;br /&gt;
2026.01.01 18:46:34.546 1: === Snapshot-Statistik ===&lt;br /&gt;
2026.01.01 18:46:34.547 1: Metric-Improvement Snapshots: 63 (letzte Epoche: 4230)&lt;br /&gt;
2026.01.01 18:46:34.549 1: Bit-Improvement Snapshots:    3 (letzte Epoche: 164)&lt;br /&gt;
2026.01.01 18:46:34.552 1: Bit-Tradeoff Snapshots:       0 (letzte Epoche: 0)&lt;br /&gt;
2026.01.01 18:46:34.559 1: SolCast DEBUG&amp;gt; Best Snapshot reloaded from Epoche 4230: Train MSE=0.000175, Val MSE=0.000309, Val MAE=0.012845, Val MedAE=0.008584, Bit_Fail=0,&lt;br /&gt;
2026.01.01 18:46:34.561 1: SolCast DEBUG&amp;gt; Run Validation Test with 20% of Input data ...&lt;br /&gt;
2026.01.01 18:46:34.602 1: SolCast DEBUG&amp;gt; Validation finished - Best Training MSE=0.000175, Validation MSE=0.000309, Validation Bit_Fail=0&lt;br /&gt;
2026.01.01 18:46:34.605 1: SolCast DEBUG&amp;gt; Retrain check -&amp;gt; &lt;br /&gt;
-- In Normalization Space: -- &lt;br /&gt;
Train MSE=0.000175 &lt;br /&gt;
Val MSE=0.000309 &lt;br /&gt;
Val Mean=0.0003042089 &lt;br /&gt;
VAL/TRAIN MSE Ratio=1.763249 (limit=2.5) &lt;br /&gt;
Diff=0.000134 (limit=0.005) &lt;br /&gt;
ValStd=0.0000076839 (limit=7.60522365479913e-05) &lt;br /&gt;
-- At Original Scale: -- &lt;br /&gt;
MAE=211.576764064665 &lt;br /&gt;
RMSE/MAE=1.3694 (limit=1.5) &lt;br /&gt;
Slope=0.935893 (limit=0.7 .. 1.3) &lt;br /&gt;
Bias=4.36 (limit=+-105.788382032332) &lt;br /&gt;
R2=0.890528595577006 &lt;br /&gt;
P95=585.8856 (limit=846.307056258658) &lt;br /&gt;
P99=968.7970 (limit=1692.61411251732) &lt;br /&gt;
-- Robustness Indicators: -- &lt;br /&gt;
RMSE relative=62 (limit=20) &lt;br /&gt;
BitFail=0 (limit=5) &lt;br /&gt;
BitFailRate=0.0000 (limit=0.1) &lt;br /&gt;
-&amp;gt; Retrain&lt;br /&gt;
2026.01.01 18:46:34.613 1: SolCast DEBUG&amp;gt; Retry attempt 2 with Seed=16325084&lt;br /&gt;
2026.01.01 18:46:34.619 1: SolCast DEBUG&amp;gt; AI FANN Training started with Params:&lt;br /&gt;
num input datasets=7314, &lt;br /&gt;
training algo=FANN_TRAIN_INCREMENTAL, &lt;br /&gt;
output AF=LINEAR, &lt;br /&gt;
hidden AF=SIGMOID, &lt;br /&gt;
hidden Neurons=80,40,20, &lt;br /&gt;
hidden steepness=0.9, &lt;br /&gt;
Epoches=15000, &lt;br /&gt;
mse_error=0.001, &lt;br /&gt;
learning rate=0.00500, &lt;br /&gt;
learning momentum=0.7, &lt;br /&gt;
Data sharing=split after shuffle of training data and use AI internal shuffle (Train=5851, Test=1462), &lt;br /&gt;
Data shuffle=2 (period=10)&lt;br /&gt;
2026.01.01 18:46:34.804 1: SolCast DEBUG&amp;gt; Epoche 1: Train MSE=0.002232, Val MSE=0.002836, Val MAE=0.031928, Val MedAE=0.027901, Bit_Fail=2 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:46:35.250 1: SolCast DEBUG&amp;gt; Epoche 4: Train MSE=0.002191, Val MSE=0.002835, Val MAE=0.031923, Val MedAE=0.027895, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:35.703 1: SolCast DEBUG&amp;gt; Epoche 7: Train MSE=0.002187, Val MSE=0.002834, Val MAE=0.031919, Val MedAE=0.027892, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:42.846 1: SolCast DEBUG&amp;gt; Epoche 54: Train MSE=0.002012, Val MSE=0.002830, Val MAE=0.030056, Val MedAE=0.024398, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:42.997 1: SolCast DEBUG&amp;gt; Epoche 55: Train MSE=0.001999, Val MSE=0.002816, Val MAE=0.029980, Val MedAE=0.024096, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:43.151 1: SolCast DEBUG&amp;gt; Epoche 56: Train MSE=0.001984, Val MSE=0.002799, Val MAE=0.029892, Val MedAE=0.023790, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:43.302 1: SolCast DEBUG&amp;gt; Epoche 57: Train MSE=0.001966, Val MSE=0.002780, Val MAE=0.029791, Val MedAE=0.023427, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:43.459 1: SolCast DEBUG&amp;gt; Epoche 58: Train MSE=0.001945, Val MSE=0.002756, Val MAE=0.029676, Val MedAE=0.022958, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:43.623 1: SolCast DEBUG&amp;gt; Epoche 59: Train MSE=0.001920, Val MSE=0.002728, Val MAE=0.029540, Val MedAE=0.022374, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:44.667 1: SolCast DEBUG&amp;gt; Epoche 65: Train MSE=0.001639, Val MSE=0.002678, Val MAE=0.029156, Val MedAE=0.016122, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:50.165 1: SolCast DEBUG&amp;gt; Epoche 100: Train MSE=0.001639, Val MSE=0.001617, Val MAE=0.027389, Val MedAE=0.021329, Bit_Fail=1&lt;br /&gt;
2026.01.01 18:46:57.117 1: SolCast DEBUG&amp;gt; Epoche 140: Train MSE=0.000582, Val MSE=0.000982, Val MAE=0.021762, Val MedAE=0.016481, Bit_Fail=1 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:46:57.374 1: SolCast DEBUG&amp;gt; Epoche 141: Train MSE=0.000571, Val MSE=0.000963, Val MAE=0.021553, Val MedAE=0.016314, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:57.625 1: SolCast DEBUG&amp;gt; Epoche 142: Train MSE=0.000559, Val MSE=0.000944, Val MAE=0.021340, Val MedAE=0.015998, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:57.814 1: SolCast DEBUG&amp;gt; Epoche 143: Train MSE=0.000548, Val MSE=0.000925, Val MAE=0.021128, Val MedAE=0.015847, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:58.048 1: SolCast DEBUG&amp;gt; Epoche 144: Train MSE=0.000537, Val MSE=0.000906, Val MAE=0.020921, Val MedAE=0.015525, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:58.217 1: SolCast DEBUG&amp;gt; Epoche 145: Train MSE=0.000526, Val MSE=0.000888, Val MAE=0.020716, Val MedAE=0.015427, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:58.387 1: SolCast DEBUG&amp;gt; Epoche 146: Train MSE=0.000516, Val MSE=0.000871, Val MAE=0.020515, Val MedAE=0.015357, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:58.797 1: SolCast DEBUG&amp;gt; Epoche 148: Train MSE=0.000497, Val MSE=0.000838, Val MAE=0.020132, Val MedAE=0.015318, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:58.986 1: SolCast DEBUG&amp;gt; Epoche 149: Train MSE=0.000488, Val MSE=0.000822, Val MAE=0.019953, Val MedAE=0.015200, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:59.141 1: SolCast DEBUG&amp;gt; Epoche 150: Train MSE=0.000482, Val MSE=0.000817, Val MAE=0.019792, Val MedAE=0.015107, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:59.316 1: SolCast DEBUG&amp;gt; Epoche 151: Train MSE=0.000474, Val MSE=0.000802, Val MAE=0.019630, Val MedAE=0.014972, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:59.471 1: SolCast DEBUG&amp;gt; Epoche 152: Train MSE=0.000466, Val MSE=0.000788, Val MAE=0.019477, Val MedAE=0.014905, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:59.637 1: SolCast DEBUG&amp;gt; Epoche 153: Train MSE=0.000459, Val MSE=0.000775, Val MAE=0.019332, Val MedAE=0.014836, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:59.795 1: SolCast DEBUG&amp;gt; Epoche 154: Train MSE=0.000452, Val MSE=0.000763, Val MAE=0.019196, Val MedAE=0.014833, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:59.953 1: SolCast DEBUG&amp;gt; Epoche 155: Train MSE=0.000446, Val MSE=0.000751, Val MAE=0.019068, Val MedAE=0.014766, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:00.128 1: SolCast DEBUG&amp;gt; Epoche 156: Train MSE=0.000440, Val MSE=0.000740, Val MAE=0.018949, Val MedAE=0.014751, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:00.423 1: SolCast DEBUG&amp;gt; Epoche 157: Train MSE=0.000434, Val MSE=0.000729, Val MAE=0.018837, Val MedAE=0.014571, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:00.580 1: SolCast DEBUG&amp;gt; Epoche 158: Train MSE=0.000429, Val MSE=0.000719, Val MAE=0.018732, Val MedAE=0.014399, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:00.738 1: SolCast DEBUG&amp;gt; Epoche 159: Train MSE=0.000423, Val MSE=0.000710, Val MAE=0.018632, Val MedAE=0.014296, Bit_Fail=0 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:47:04.664 1: SolCast DEBUG&amp;gt; Epoche 185: Train MSE=0.000352, Val MSE=0.000570, Val MAE=0.017726, Val MedAE=0.014241, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:04.823 1: SolCast DEBUG&amp;gt; Epoche 186: Train MSE=0.000351, Val MSE=0.000568, Val MAE=0.017700, Val MedAE=0.014157, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:04.998 1: SolCast DEBUG&amp;gt; Epoche 187: Train MSE=0.000350, Val MSE=0.000567, Val MAE=0.017676, Val MedAE=0.014128, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:05.330 1: SolCast DEBUG&amp;gt; Epoche 189: Train MSE=0.000347, Val MSE=0.000565, Val MAE=0.017630, Val MedAE=0.014111, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:07.326 1: SolCast DEBUG&amp;gt; Epoche 200: Train MSE=0.000347, Val MSE=0.000560, Val MAE=0.017645, Val MedAE=0.014294, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:47:08.430 1: SolCast DEBUG&amp;gt; Epoche 207: Train MSE=0.000336, Val MSE=0.000557, Val MAE=0.017581, Val MedAE=0.014098, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:08.925 1: SolCast DEBUG&amp;gt; Epoche 210: Train MSE=0.000332, Val MSE=0.000551, Val MAE=0.017149, Val MedAE=0.014015, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:09.251 1: SolCast DEBUG&amp;gt; Epoche 212: Train MSE=0.000331, Val MSE=0.000549, Val MAE=0.017106, Val MedAE=0.014013, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:09.543 1: SolCast DEBUG&amp;gt; Epoche 214: Train MSE=0.000330, Val MSE=0.000548, Val MAE=0.017079, Val MedAE=0.014009, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:19.704 1: SolCast DEBUG&amp;gt; Epoche 280: Train MSE=0.000312, Val MSE=0.000539, Val MAE=0.016444, Val MedAE=0.013594, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:22.914 1: SolCast DEBUG&amp;gt; Epoche 300: Train MSE=0.000312, Val MSE=0.000547, Val MAE=0.017776, Val MedAE=0.014873, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:47:36.920 1: SolCast DEBUG&amp;gt; Epoche 390: Train MSE=0.000299, Val MSE=0.000534, Val MAE=0.016256, Val MedAE=0.013227, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:37.075 1: SolCast DEBUG&amp;gt; Epoche 391: Train MSE=0.000299, Val MSE=0.000533, Val MAE=0.016248, Val MedAE=0.013207, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:37.692 1: SolCast DEBUG&amp;gt; Epoche 395: Train MSE=0.000298, Val MSE=0.000532, Val MAE=0.016231, Val MedAE=0.013184, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:38.408 1: SolCast DEBUG&amp;gt; Epoche 400: Train MSE=0.000298, Val MSE=0.000533, Val MAE=0.016139, Val MedAE=0.013128, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:47:43.011 1: SolCast DEBUG&amp;gt; Epoche 430: Train MSE=0.000294, Val MSE=0.000524, Val MAE=0.016053, Val MedAE=0.013160, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:53.755 1: SolCast DEBUG&amp;gt; Epoche 500: Train MSE=0.000294, Val MSE=0.000533, Val MAE=0.017601, Val MedAE=0.015372, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:48:03.268 1: SolCast DEBUG&amp;gt; Epoche 560: Train MSE=0.000278, Val MSE=0.000499, Val MAE=0.015935, Val MedAE=0.013052, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:48:10.654 1: SolCast DEBUG&amp;gt; Epoche 600: Train MSE=0.000278, Val MSE=0.000497, Val MAE=0.016063, Val MedAE=0.013071, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:48:17.120 1: SolCast DEBUG&amp;gt; Epoche 640: Train MSE=0.000270, Val MSE=0.000494, Val MAE=0.015925, Val MedAE=0.012746, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:48:26.254 1: SolCast DEBUG&amp;gt; Epoche 700: Train MSE=0.000270, Val MSE=0.000494, Val MAE=0.016121, Val MedAE=0.012865, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:48:41.338 1: SolCast DEBUG&amp;gt; Epoche 800: Train MSE=0.000270, Val MSE=0.000496, Val MAE=0.016486, Val MedAE=0.013111, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:48:50.270 1: SolCast DEBUG&amp;gt; Epoche 860: Train MSE=0.000251, Val MSE=0.000491, Val MAE=0.015786, Val MedAE=0.012241, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:48:56.298 1: SolCast DEBUG&amp;gt; Epoche 900: Train MSE=0.000251, Val MSE=0.000539, Val MAE=0.017781, Val MedAE=0.014813, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:49:00.767 1: openMeteo - Open-Meteo API server response: start_SSL https://api.open-meteo.com:443 timed out&lt;br /&gt;
2026.01.01 18:49:11.666 1: SolCast DEBUG&amp;gt; Epoche 1000: Train MSE=0.000251, Val MSE=0.000487, Val MAE=0.015740, Val MedAE=0.012296, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:49:28.665 1: SolCast DEBUG&amp;gt; Epoche 1100: Train MSE=0.000251, Val MSE=0.000491, Val MAE=0.015728, Val MedAE=0.012462, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:49:39.207 1: SolCast DEBUG&amp;gt; Epoche 1168: Train MSE=0.000235, Val MSE=0.000479, Val MAE=0.015557, Val MedAE=0.012237, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:49:44.096 1: SolCast DEBUG&amp;gt; Epoche 1200: Train MSE=0.000235, Val MSE=0.000477, Val MAE=0.015613, Val MedAE=0.012266, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:49:59.330 1: SolCast DEBUG&amp;gt; Epoche 1300: Train MSE=0.000235, Val MSE=0.000469, Val MAE=0.015970, Val MedAE=0.012473, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:50:02.607 1: SolCast DEBUG&amp;gt; Epoche 1320: Train MSE=0.000230, Val MSE=0.000474, Val MAE=0.015490, Val MedAE=0.011887, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:50:15.063 1: SolCast DEBUG&amp;gt; Epoche 1400: Train MSE=0.000230, Val MSE=0.000469, Val MAE=0.016083, Val MedAE=0.012479, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:50:31.357 1: SolCast DEBUG&amp;gt; Epoche 1500: Train MSE=0.000230, Val MSE=0.000461, Val MAE=0.015731, Val MedAE=0.012435, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:50:43.405 1: SolCast DEBUG&amp;gt; Epoche 1570: Train MSE=0.000219, Val MSE=0.000452, Val MAE=0.015217, Val MedAE=0.011832, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:50:48.687 1: SolCast DEBUG&amp;gt; Epoche 1600: Train MSE=0.000219, Val MSE=0.000452, Val MAE=0.015676, Val MedAE=0.012380, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:51:00.785 1: SolCast DEBUG&amp;gt; Epoche 1680: Train MSE=0.000216, Val MSE=0.000447, Val MAE=0.015153, Val MedAE=0.011761, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:51:02.263 1: SolCast DEBUG&amp;gt; Epoche 1690: Train MSE=0.000215, Val MSE=0.000446, Val MAE=0.015014, Val MedAE=0.011740, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:51:03.808 1: SolCast DEBUG&amp;gt; Epoche 1700: Train MSE=0.000215, Val MSE=0.000444, Val MAE=0.015548, Val MedAE=0.012346, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:51:19.267 1: SolCast DEBUG&amp;gt; Epoche 1800: Train MSE=0.000215, Val MSE=0.000456, Val MAE=0.016255, Val MedAE=0.012272, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:51:28.478 1: SolCast DEBUG&amp;gt; Epoche 1860: Train MSE=0.000211, Val MSE=0.000430, Val MAE=0.014967, Val MedAE=0.011675, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:51:32.128 1: SolCast DEBUG&amp;gt; Epoche 1885: Train MSE=0.000210, Val MSE=0.000429, Val MAE=0.014936, Val MedAE=0.011634, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:51:34.991 1: SolCast DEBUG&amp;gt; Epoche 1900: Train MSE=0.000210, Val MSE=0.000431, Val MAE=0.015557, Val MedAE=0.012006, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:51:36.961 1: SolCast DEBUG&amp;gt; Epoche 1910: Train MSE=0.000209, Val MSE=0.000427, Val MAE=0.014927, Val MedAE=0.011633, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:51:44.135 1: SolCast DEBUG&amp;gt; Epoche 1950: Train MSE=0.000207, Val MSE=0.000425, Val MAE=0.014852, Val MedAE=0.011568, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:51:51.659 1: SolCast DEBUG&amp;gt; Epoche 2000: Train MSE=0.000207, Val MSE=0.000419, Val MAE=0.015028, Val MedAE=0.011705, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:52:07.280 1: SolCast DEBUG&amp;gt; Epoche 2100: Train MSE=0.000207, Val MSE=0.000419, Val MAE=0.015127, Val MedAE=0.011801, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:52:22.353 1: SolCast DEBUG&amp;gt; Epoche 2200: Train MSE=0.000207, Val MSE=0.000409, Val MAE=0.014933, Val MedAE=0.011578, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:52:25.518 1: SolCast DEBUG&amp;gt; Epoche 2220: Train MSE=0.000201, Val MSE=0.000401, Val MAE=0.014505, Val MedAE=0.011123, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:52:38.140 1: SolCast DEBUG&amp;gt; Epoche 2280: Train MSE=0.000200, Val MSE=0.000398, Val MAE=0.014426, Val MedAE=0.010998, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:52:40.466 1: SolCast DEBUG&amp;gt; Epoche 2290: Train MSE=0.000199, Val MSE=0.000397, Val MAE=0.014408, Val MedAE=0.010918, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:52:42.754 1: SolCast DEBUG&amp;gt; Epoche 2300: Train MSE=0.000199, Val MSE=0.000395, Val MAE=0.014771, Val MedAE=0.011372, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:53:06.020 1: SolCast DEBUG&amp;gt; Epoche 2400: Train MSE=0.000199, Val MSE=0.000386, Val MAE=0.014179, Val MedAE=0.010473, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:53:06.031 1: SolCast DEBUG&amp;gt; Epoche 2400: Train MSE=0.000196, Val MSE=0.000386, Val MAE=0.014179, Val MedAE=0.010473, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:53:27.648 1: SolCast DEBUG&amp;gt; Epoche 2500: Train MSE=0.000196, Val MSE=0.000394, Val MAE=0.015055, Val MedAE=0.011719, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:53:48.669 1: SolCast DEBUG&amp;gt; Epoche 2600: Train MSE=0.000196, Val MSE=0.000393, Val MAE=0.015223, Val MedAE=0.011833, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:54:04.615 1: SolCast DEBUG&amp;gt; Epoche 2670: Train MSE=0.000190, Val MSE=0.000363, Val MAE=0.014023, Val MedAE=0.010343, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:54:10.539 1: SolCast DEBUG&amp;gt; Epoche 2700: Train MSE=0.000190, Val MSE=0.000399, Val MAE=0.015520, Val MedAE=0.012166, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:54:22.630 1: SolCast DEBUG&amp;gt; Epoche 2762: Train MSE=0.000188, Val MSE=0.000359, Val MAE=0.014009, Val MedAE=0.010303, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:54:28.642 1: SolCast DEBUG&amp;gt; Epoche 2800: Train MSE=0.000188, Val MSE=0.000422, Val MAE=0.016216, Val MedAE=0.013541, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:54:36.250 1: SolCast DEBUG&amp;gt; Epoche 2850: Train MSE=0.000187, Val MSE=0.000356, Val MAE=0.013892, Val MedAE=0.010014, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:54:37.817 1: SolCast DEBUG&amp;gt; Epoche 2860: Train MSE=0.000186, Val MSE=0.000353, Val MAE=0.013781, Val MedAE=0.009785, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:54:43.894 1: SolCast DEBUG&amp;gt; Epoche 2900: Train MSE=0.000186, Val MSE=0.000373, Val MAE=0.014968, Val MedAE=0.011754, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:54:51.665 1: SolCast DEBUG&amp;gt; Epoche 2950: Train MSE=0.000184, Val MSE=0.000350, Val MAE=0.013709, Val MedAE=0.009744, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:54:56.355 1: SolCast DEBUG&amp;gt; Epoche 2980: Train MSE=0.000185, Val MSE=0.000344, Val MAE=0.013542, Val MedAE=0.009640, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:54:59.391 1: SolCast DEBUG&amp;gt; Epoche 3000: Train MSE=0.000185, Val MSE=0.000345, Val MAE=0.013771, Val MedAE=0.010299, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:55:15.914 1: SolCast DEBUG&amp;gt; Epoche 3100: Train MSE=0.000185, Val MSE=0.000338, Val MAE=0.013390, Val MedAE=0.009239, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:55:15.920 1: SolCast DEBUG&amp;gt; Epoche 3100: Train MSE=0.000183, Val MSE=0.000338, Val MAE=0.013390, Val MedAE=0.009239, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:55:31.223 1: SolCast DEBUG&amp;gt; Epoche 3200: Train MSE=0.000183, Val MSE=0.000374, Val MAE=0.015348, Val MedAE=0.013113, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:55:46.650 1: SolCast DEBUG&amp;gt; Epoche 3300: Train MSE=0.000183, Val MSE=0.000395, Val MAE=0.015892, Val MedAE=0.013867, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:55:55.663 1: SolCast DEBUG&amp;gt; Epoche 3360: Train MSE=0.000178, Val MSE=0.000336, Val MAE=0.013102, Val MedAE=0.009038, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:55:57.156 1: SolCast DEBUG&amp;gt; Epoche 3370: Train MSE=0.000178, Val MSE=0.000328, Val MAE=0.013027, Val MedAE=0.008576, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:56:01.837 1: SolCast DEBUG&amp;gt; Epoche 3400: Train MSE=0.000178, Val MSE=0.000331, Val MAE=0.013966, Val MedAE=0.010989, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:56:18.127 1: SolCast DEBUG&amp;gt; Epoche 3500: Train MSE=0.000178, Val MSE=0.000317, Val MAE=0.013546, Val MedAE=0.010578, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:56:33.705 1: SolCast DEBUG&amp;gt; Epoche 3600: Train MSE=0.000178, Val MSE=0.000326, Val MAE=0.013924, Val MedAE=0.011087, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:56:49.380 1: SolCast DEBUG&amp;gt; Epoche 3700: Train MSE=0.000178, Val MSE=0.000313, Val MAE=0.013647, Val MedAE=0.011350, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:57:04.360 1: SolCast DEBUG&amp;gt; Epoche 3800: Train MSE=0.000178, Val MSE=0.000315, Val MAE=0.013759, Val MedAE=0.011353, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:57:20.079 1: SolCast DEBUG&amp;gt; Epoche 3900: Train MSE=0.000178, Val MSE=0.000317, Val MAE=0.013889, Val MedAE=0.011544, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:57:36.568 1: SolCast DEBUG&amp;gt; Epoche 4000: Train MSE=0.000178, Val MSE=0.000303, Val MAE=0.013266, Val MedAE=0.010514, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:57:51.815 1: SolCast DEBUG&amp;gt; Epoche 4100: Train MSE=0.000178, Val MSE=0.000297, Val MAE=0.013051, Val MedAE=0.010491, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:58:07.665 1: SolCast DEBUG&amp;gt; Epoche 4200: Train MSE=0.000178, Val MSE=0.000298, Val MAE=0.013165, Val MedAE=0.010657, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:58:22.874 1: SolCast DEBUG&amp;gt; Epoche 4300: Train MSE=0.000178, Val MSE=0.000299, Val MAE=0.012652, Val MedAE=0.009298, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:58:39.872 1: SolCast DEBUG&amp;gt; Epoche 4400: Train MSE=0.000178, Val MSE=0.000299, Val MAE=0.013357, Val MedAE=0.010952, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:58:55.060 1: SolCast DEBUG&amp;gt; Epoche 4500: Train MSE=0.000178, Val MSE=0.000293, Val MAE=0.012888, Val MedAE=0.010075, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:59:10.645 1: SolCast DEBUG&amp;gt; Epoche 4600: Train MSE=0.000178, Val MSE=0.000296, Val MAE=0.013170, Val MedAE=0.010801, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:59:26.299 1: SolCast DEBUG&amp;gt; Epoche 4700: Train MSE=0.000178, Val MSE=0.000289, Val MAE=0.012813, Val MedAE=0.010297, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:59:41.390 1: SolCast DEBUG&amp;gt; Epoche 4800: Train MSE=0.000178, Val MSE=0.000288, Val MAE=0.012730, Val MedAE=0.010022, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:59:58.018 1: SolCast DEBUG&amp;gt; Epoche 4900: Train MSE=0.000178, Val MSE=0.000288, Val MAE=0.012927, Val MedAE=0.010486, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:00:16.580 1: SolCast DEBUG&amp;gt; Epoche 5000: Train MSE=0.000178, Val MSE=0.000300, Val MAE=0.013538, Val MedAE=0.011570, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:00:22.430 1: VRMAPI DEBUG&amp;gt; start add AI raw data for hour: 19&lt;br /&gt;
2026.01.01 19:00:22.434 1: VRMAPI DEBUG&amp;gt; AI raw add - 1 entities added to raw data pool (set verbose 4 for output more detail)&lt;br /&gt;
2026.01.01 19:00:22.507 1: VRMAPI DEBUG&amp;gt; AI raw data saved into file: ./FHEM/FhemUtils/AIraw_SolarForecast_VRMAPI&lt;br /&gt;
2026.01.01 19:00:23.036 1: SolCast DEBUG&amp;gt; start add AI raw data for hour: 19&lt;br /&gt;
2026.01.01 19:00:23.041 1: SolCast DEBUG&amp;gt; AI raw add - 1 entities added to raw data pool (set verbose 4 for output more detail)&lt;br /&gt;
2026.01.01 19:00:23.490 1: SolCast DEBUG&amp;gt; AI raw data saved into file: ./FHEM/FhemUtils/AIraw_SolarForecast_SolCast&lt;br /&gt;
2026.01.01 19:00:25.468 1: openMeteo DEBUG&amp;gt; start add AI raw data for hour: 19&lt;br /&gt;
2026.01.01 19:00:25.471 1: openMeteo DEBUG&amp;gt; AI raw add - 1 entities added to raw data pool (set verbose 4 for output more detail)&lt;br /&gt;
2026.01.01 19:00:25.529 1: openMeteo DEBUG&amp;gt; AI raw data saved into file: ./FHEM/FhemUtils/AIraw_SolarForecast_openMeteo&lt;br /&gt;
2026.01.01 19:00:36.434 1: SolCast DEBUG&amp;gt; Epoche 5100: Train MSE=0.000178, Val MSE=0.000287, Val MAE=0.012656, Val MedAE=0.009749, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:00:52.824 1: SolCast DEBUG&amp;gt; Epoche 5200: Train MSE=0.000178, Val MSE=0.000315, Val MAE=0.014053, Val MedAE=0.012264, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:01:08.326 1: SolCast DEBUG&amp;gt; Epoche 5300: Train MSE=0.000178, Val MSE=0.000291, Val MAE=0.013064, Val MedAE=0.010484, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:01:18.912 1: SolCast DEBUG&amp;gt; Early stopping bei Epoche 5370 (no improvement since 2000 epochs)&lt;br /&gt;
2026.01.01 19:01:18.914 1: === Snapshot-Statistik ===&lt;br /&gt;
2026.01.01 19:01:18.916 1: Metric-Improvement Snapshots: 64 (letzte Epoche: 3370)&lt;br /&gt;
2026.01.01 19:01:18.918 1: Bit-Improvement Snapshots:    3 (letzte Epoche: 159)&lt;br /&gt;
2026.01.01 19:01:18.919 1: Bit-Tradeoff Snapshots:       0 (letzte Epoche: 0)&lt;br /&gt;
2026.01.01 19:01:18.925 1: SolCast DEBUG&amp;gt; Best Snapshot reloaded from Epoche 3370: Train MSE=0.000178, Val MSE=0.000328, Val MAE=0.013027, Val MedAE=0.008576, Bit_Fail=0,&lt;br /&gt;
2026.01.01 19:01:18.927 1: SolCast DEBUG&amp;gt; Run Validation Test with 20% of Input data ...&lt;br /&gt;
2026.01.01 19:01:18.969 1: SolCast DEBUG&amp;gt; Validation finished - Best Training MSE=0.000178, Validation MSE=0.000328, Validation Bit_Fail=0&lt;br /&gt;
2026.01.01 19:01:18.971 1: SolCast DEBUG&amp;gt; Retrain check -&amp;gt; &lt;br /&gt;
-- In Normalization Space: -- &lt;br /&gt;
Train MSE=0.000178 &lt;br /&gt;
Val MSE=0.000328 &lt;br /&gt;
Val Mean=0.0002956156 &lt;br /&gt;
VAL/TRAIN MSE Ratio=1.837433 (limit=2.5) &lt;br /&gt;
Diff=0.000149 (limit=0.005) &lt;br /&gt;
ValStd=0.0000173294 (limit=7.39038913958514e-05) &lt;br /&gt;
-- At Original Scale: -- &lt;br /&gt;
MAE=214.560321844596 &lt;br /&gt;
RMSE/MAE=1.3893 (limit=1.5) &lt;br /&gt;
Slope=0.916647 (limit=0.7 .. 1.3) &lt;br /&gt;
Bias=2.25 (limit=+-107.280160922298) &lt;br /&gt;
R2=0.884124888835566 &lt;br /&gt;
P95=585.2166 (limit=858.241287378382) &lt;br /&gt;
P99=942.9805 (limit=1716.48257475676) &lt;br /&gt;
-- Robustness Indicators: -- &lt;br /&gt;
RMSE relative=64 (limit=20) &lt;br /&gt;
BitFail=0 (limit=5) &lt;br /&gt;
BitFailRate=0.0000 (limit=0.1) &lt;br /&gt;
-&amp;gt; Retrain&lt;br /&gt;
2026.01.01 19:01:18.979 1: SolCast DEBUG&amp;gt; Retry attempt 3 with Seed=16689959&lt;br /&gt;
2026.01.01 19:01:18.985 1: SolCast DEBUG&amp;gt; AI FANN Training started with Params:&lt;br /&gt;
num input datasets=7314, &lt;br /&gt;
training algo=FANN_TRAIN_INCREMENTAL, &lt;br /&gt;
output AF=LINEAR, &lt;br /&gt;
hidden AF=SIGMOID, &lt;br /&gt;
hidden Neurons=80,40,20, &lt;br /&gt;
hidden steepness=0.9, &lt;br /&gt;
Epoches=15000, &lt;br /&gt;
mse_error=0.001, &lt;br /&gt;
learning rate=0.00500, &lt;br /&gt;
learning momentum=0.7, &lt;br /&gt;
Data sharing=split after shuffle of training data and use AI internal shuffle (Train=5851, Test=1462), &lt;br /&gt;
Data shuffle=2 (period=10)&lt;br /&gt;
2026.01.01 19:01:19.145 1: SolCast DEBUG&amp;gt; Epoche 1: Train MSE=0.002202, Val MSE=0.002839, Val MAE=0.031937, Val MedAE=0.027914, Bit_Fail=2 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 19:01:25.133 1: SolCast DEBUG&amp;gt; Epoche 40: Train MSE=0.002098, Val MSE=0.002825, Val MAE=0.031158, Val MedAE=0.027367, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:27.800 1: SolCast DEBUG&amp;gt; Epoche 57: Train MSE=0.001969, Val MSE=0.002810, Val MAE=0.029915, Val MedAE=0.021870, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:27.982 1: SolCast DEBUG&amp;gt; Epoche 58: Train MSE=0.001947, Val MSE=0.002786, Val MAE=0.029801, Val MedAE=0.021464, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:28.134 1: SolCast DEBUG&amp;gt; Epoche 59: Train MSE=0.001921, Val MSE=0.002758, Val MAE=0.029673, Val MedAE=0.020903, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:28.609 1: SolCast DEBUG&amp;gt; Epoche 62: Train MSE=0.001810, Val MSE=0.002716, Val MAE=0.029480, Val MedAE=0.017887, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:28.767 1: SolCast DEBUG&amp;gt; Epoche 63: Train MSE=0.001761, Val MSE=0.002660, Val MAE=0.029224, Val MedAE=0.017446, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:28.915 1: SolCast DEBUG&amp;gt; Epoche 64: Train MSE=0.001706, Val MSE=0.002597, Val MAE=0.028944, Val MedAE=0.016968, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:29.063 1: SolCast DEBUG&amp;gt; Epoche 65: Train MSE=0.001645, Val MSE=0.002528, Val MAE=0.028652, Val MedAE=0.016879, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:29.207 1: SolCast DEBUG&amp;gt; Epoche 66: Train MSE=0.001581, Val MSE=0.002455, Val MAE=0.028362, Val MedAE=0.016529, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:34.406 1: SolCast DEBUG&amp;gt; Epoche 100: Train MSE=0.001581, Val MSE=0.001674, Val MAE=0.026943, Val MedAE=0.019938, Bit_Fail=1&lt;br /&gt;
2026.01.01 19:01:41.897 1: SolCast DEBUG&amp;gt; Epoche 149: Train MSE=0.000574, Val MSE=0.000953, Val MAE=0.021557, Val MedAE=0.017213, Bit_Fail=1 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 19:01:43.755 1: SolCast DEBUG&amp;gt; Epoche 160: Train MSE=0.000466, Val MSE=0.000806, Val MAE=0.019501, Val MedAE=0.014848, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:43.926 1: SolCast DEBUG&amp;gt; Epoche 161: Train MSE=0.000458, Val MSE=0.000792, Val MAE=0.019351, Val MedAE=0.014777, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:44.118 1: SolCast DEBUG&amp;gt; Epoche 162: Train MSE=0.000451, Val MSE=0.000778, Val MAE=0.019209, Val MedAE=0.014629, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:44.334 1: SolCast DEBUG&amp;gt; Epoche 163: Train MSE=0.000444, Val MSE=0.000764, Val MAE=0.019075, Val MedAE=0.014565, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:44.504 1: SolCast DEBUG&amp;gt; Epoche 164: Train MSE=0.000438, Val MSE=0.000752, Val MAE=0.018948, Val MedAE=0.014360, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:44.716 1: SolCast DEBUG&amp;gt; Epoche 165: Train MSE=0.000432, Val MSE=0.000740, Val MAE=0.018829, Val MedAE=0.014227, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:44.952 1: SolCast DEBUG&amp;gt; Epoche 166: Train MSE=0.000426, Val MSE=0.000729, Val MAE=0.018714, Val MedAE=0.014165, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:45.151 1: SolCast DEBUG&amp;gt; Epoche 167: Train MSE=0.000421, Val MSE=0.000718, Val MAE=0.018605, Val MedAE=0.014070, Bit_Fail=0 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 19:01:45.311 1: SolCast DEBUG&amp;gt; Epoche 168: Train MSE=0.000416, Val MSE=0.000708, Val MAE=0.018500, Val MedAE=0.013993, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:45.475 1: SolCast DEBUG&amp;gt; Epoche 169: Train MSE=0.000411, Val MSE=0.000699, Val MAE=0.018400, Val MedAE=0.013928, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:50.312 1: SolCast DEBUG&amp;gt; Epoche 200: Train MSE=0.000411, Val MSE=0.000558, Val MAE=0.017252, Val MedAE=0.013991, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:01:50.478 1: SolCast DEBUG&amp;gt; Epoche 201: Train MSE=0.000341, Val MSE=0.000558, Val MAE=0.017237, Val MedAE=0.013915, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:50.920 1: SolCast DEBUG&amp;gt; Epoche 204: Train MSE=0.000338, Val MSE=0.000557, Val MAE=0.017191, Val MedAE=0.013805, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:51.226 1: SolCast DEBUG&amp;gt; Epoche 206: Train MSE=0.000337, Val MSE=0.000556, Val MAE=0.017163, Val MedAE=0.013746, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:58.095 1: SolCast DEBUG&amp;gt; Epoche 250: Train MSE=0.000319, Val MSE=0.000554, Val MAE=0.016637, Val MedAE=0.013530, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:58.382 1: SolCast DEBUG&amp;gt; Epoche 252: Train MSE=0.000318, Val MSE=0.000553, Val MAE=0.016627, Val MedAE=0.013499, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:02:00.397 1: SolCast DEBUG&amp;gt; Epoche 266: Train MSE=0.000315, Val MSE=0.000552, Val MAE=0.016535, Val MedAE=0.013373, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:02:06.185 1: SolCast DEBUG&amp;gt; Epoche 300: Train MSE=0.000315, Val MSE=0.000521, Val MAE=0.016463, Val MedAE=0.014001, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:02:17.223 1: SolCast DEBUG&amp;gt; Epoche 371: Train MSE=0.000296, Val MSE=0.000522, Val MAE=0.016217, Val MedAE=0.013366, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:02:21.515 1: SolCast DEBUG&amp;gt; Epoche 400: Train MSE=0.000296, Val MSE=0.000500, Val MAE=0.016347, Val MedAE=0.013895, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:02:23.239 1: SolCast DEBUG&amp;gt; Epoche 410: Train MSE=0.000290, Val MSE=0.000518, Val MAE=0.016152, Val MedAE=0.013203, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:02:23.555 1: SolCast DEBUG&amp;gt; Epoche 412: Train MSE=0.000290, Val MSE=0.000517, Val MAE=0.016144, Val MedAE=0.013196, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:02:24.223 1: SolCast DEBUG&amp;gt; Epoche 416: Train MSE=0.000289, Val MSE=0.000516, Val MAE=0.016133, Val MedAE=0.013144, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:02:36.913 1: SolCast DEBUG&amp;gt; Epoche 500: Train MSE=0.000289, Val MSE=0.000513, Val MAE=0.016033, Val MedAE=0.012459, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:02:36.920 1: SolCast DEBUG&amp;gt; Epoche 500: Train MSE=0.000274, Val MSE=0.000513, Val MAE=0.016033, Val MedAE=0.012459, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:02:37.941 1: SolCast DEBUG&amp;gt; Epoche 507: Train MSE=0.000273, Val MSE=0.000512, Val MAE=0.016016, Val MedAE=0.012419, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:02:52.279 1: SolCast DEBUG&amp;gt; Epoche 600: Train MSE=0.000273, Val MSE=0.000491, Val MAE=0.015793, Val MedAE=0.012659, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:03:07.863 1: SolCast DEBUG&amp;gt; Epoche 700: Train MSE=0.000273, Val MSE=0.000531, Val MAE=0.017652, Val MedAE=0.014846, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:03:22.755 1: SolCast DEBUG&amp;gt; Epoche 800: Train MSE=0.000273, Val MSE=0.000485, Val MAE=0.015777, Val MedAE=0.012388, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:03:22.761 1: SolCast DEBUG&amp;gt; Epoche 800: Train MSE=0.000246, Val MSE=0.000485, Val MAE=0.015777, Val MedAE=0.012388, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:03:38.201 1: SolCast DEBUG&amp;gt; Epoche 900: Train MSE=0.000246, Val MSE=0.000489, Val MAE=0.015804, Val MedAE=0.012387, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:03:53.934 1: SolCast DEBUG&amp;gt; Epoche 1000: Train MSE=0.000246, Val MSE=0.000491, Val MAE=0.016320, Val MedAE=0.012996, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:04:12.553 1: SolCast DEBUG&amp;gt; Epoche 1100: Train MSE=0.000246, Val MSE=0.000500, Val MAE=0.016762, Val MedAE=0.013013, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:04:29.863 1: SolCast DEBUG&amp;gt; Epoche 1200: Train MSE=0.000246, Val MSE=0.000472, Val MAE=0.015815, Val MedAE=0.012588, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:04:39.395 1: SolCast DEBUG&amp;gt; Epoche 1240: Train MSE=0.000226, Val MSE=0.000476, Val MAE=0.015690, Val MedAE=0.012238, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:04:44.449 1: SolCast DEBUG&amp;gt; Epoche 1260: Train MSE=0.000226, Val MSE=0.000472, Val MAE=0.015617, Val MedAE=0.012095, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:04:54.273 1: SolCast DEBUG&amp;gt; Epoche 1300: Train MSE=0.000226, Val MSE=0.000469, Val MAE=0.015375, Val MedAE=0.012019, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:04:54.283 1: SolCast DEBUG&amp;gt; Epoche 1300: Train MSE=0.000225, Val MSE=0.000469, Val MAE=0.015375, Val MedAE=0.012019, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:05:19.860 1: SolCast DEBUG&amp;gt; Epoche 1400: Train MSE=0.000225, Val MSE=0.000476, Val MAE=0.016232, Val MedAE=0.012583, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:05:46.230 1: SolCast DEBUG&amp;gt; Epoche 1500: Train MSE=0.000225, Val MSE=0.000460, Val MAE=0.015477, Val MedAE=0.012145, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:06:01.555 1: SolCast DEBUG&amp;gt; Epoche 1560: Train MSE=0.000215, Val MSE=0.000450, Val MAE=0.015175, Val MedAE=0.011698, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:06:11.656 1: SolCast DEBUG&amp;gt; Epoche 1600: Train MSE=0.000215, Val MSE=0.000446, Val MAE=0.015338, Val MedAE=0.011925, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:06:19.086 1: SolCast DEBUG&amp;gt; Epoche 1630: Train MSE=0.000213, Val MSE=0.000443, Val MAE=0.015005, Val MedAE=0.011380, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:06:37.018 1: SolCast DEBUG&amp;gt; Epoche 1700: Train MSE=0.000213, Val MSE=0.000456, Val MAE=0.016104, Val MedAE=0.012245, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:06:41.728 1: SolCast DEBUG&amp;gt; Epoche 1720: Train MSE=0.000209, Val MSE=0.000437, Val MAE=0.014979, Val MedAE=0.011226, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:06:54.098 1: SolCast DEBUG&amp;gt; Epoche 1770: Train MSE=0.000208, Val MSE=0.000428, Val MAE=0.014866, Val MedAE=0.011051, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:07:01.420 1: SolCast DEBUG&amp;gt; Epoche 1800: Train MSE=0.000208, Val MSE=0.000421, Val MAE=0.014909, Val MedAE=0.011181, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:07:09.022 1: SolCast DEBUG&amp;gt; Epoche 1830: Train MSE=0.000206, Val MSE=0.000425, Val MAE=0.014835, Val MedAE=0.010975, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:07:18.661 1: SolCast DEBUG&amp;gt; Epoche 1870: Train MSE=0.000205, Val MSE=0.000422, Val MAE=0.014635, Val MedAE=0.010337, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:07:26.451 1: SolCast DEBUG&amp;gt; Epoche 1900: Train MSE=0.000205, Val MSE=0.000421, Val MAE=0.015039, Val MedAE=0.011242, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:07:35.709 1: SolCast DEBUG&amp;gt; Epoche 1950: Train MSE=0.000204, Val MSE=0.000412, Val MAE=0.014563, Val MedAE=0.010315, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:07:43.401 1: SolCast DEBUG&amp;gt; Epoche 2000: Train MSE=0.000204, Val MSE=0.000478, Val MAE=0.017001, Val MedAE=0.013903, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:07:59.225 1: SolCast DEBUG&amp;gt; Epoche 2100: Train MSE=0.000204, Val MSE=0.000400, Val MAE=0.014424, Val MedAE=0.010221, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:07:59.231 1: SolCast DEBUG&amp;gt; Epoche 2100: Train MSE=0.000200, Val MSE=0.000400, Val MAE=0.014424, Val MedAE=0.010221, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:08:14.654 1: SolCast DEBUG&amp;gt; Epoche 2200: Train MSE=0.000200, Val MSE=0.000399, Val MAE=0.014978, Val MedAE=0.011324, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:08:28.453 1: SolCast DEBUG&amp;gt; Epoche 2290: Train MSE=0.000196, Val MSE=0.000390, Val MAE=0.014290, Val MedAE=0.009855, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:08:29.937 1: SolCast DEBUG&amp;gt; Epoche 2300: Train MSE=0.000196, Val MSE=0.000391, Val MAE=0.014139, Val MedAE=0.009359, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:08:46.992 1: SolCast DEBUG&amp;gt; Epoche 2400: Train MSE=0.000196, Val MSE=0.000429, Val MAE=0.016088, Val MedAE=0.013370, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:08:59.193 1: SolCast DEBUG&amp;gt; Epoche 2480: Train MSE=0.000193, Val MSE=0.000378, Val MAE=0.014148, Val MedAE=0.009492, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:09:02.241 1: SolCast DEBUG&amp;gt; Epoche 2500: Train MSE=0.000193, Val MSE=0.000384, Val MAE=0.014816, Val MedAE=0.011437, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:09:18.312 1: SolCast DEBUG&amp;gt; Epoche 2600: Train MSE=0.000193, Val MSE=0.000373, Val MAE=0.014435, Val MedAE=0.010892, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:09:27.592 1: SolCast DEBUG&amp;gt; Epoche 2660: Train MSE=0.000190, Val MSE=0.000367, Val MAE=0.013899, Val MedAE=0.009407, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:09:33.631 1: SolCast DEBUG&amp;gt; Epoche 2700: Train MSE=0.000190, Val MSE=0.000364, Val MAE=0.014131, Val MedAE=0.010351, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:09:50.479 1: SolCast DEBUG&amp;gt; Epoche 2800: Train MSE=0.000190, Val MSE=0.000374, Val MAE=0.014829, Val MedAE=0.011905, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:10:06.433 1: SolCast DEBUG&amp;gt; Epoche 2900: Train MSE=0.000190, Val MSE=0.000358, Val MAE=0.013816, Val MedAE=0.009626, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:10:17.130 1: SolCast DEBUG&amp;gt; Epoche 2970: Train MSE=0.000184, Val MSE=0.000354, Val MAE=0.013688, Val MedAE=0.009390, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:10:21.510 1: SolCast DEBUG&amp;gt; Epoche 3000: Train MSE=0.000184, Val MSE=0.000376, Val MAE=0.015092, Val MedAE=0.012492, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:10:37.294 1: SolCast DEBUG&amp;gt; Epoche 3100: Train MSE=0.000184, Val MSE=0.000344, Val MAE=0.013896, Val MedAE=0.010700, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:10:52.935 1: SolCast DEBUG&amp;gt; Epoche 3200: Train MSE=0.000184, Val MSE=0.000340, Val MAE=0.013841, Val MedAE=0.010725, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:11:09.459 1: SolCast DEBUG&amp;gt; Epoche 3300: Train MSE=0.000184, Val MSE=0.000343, Val MAE=0.014114, Val MedAE=0.011228, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:11:25.191 1: SolCast DEBUG&amp;gt; Epoche 3400: Train MSE=0.000184, Val MSE=0.000329, Val MAE=0.013537, Val MedAE=0.010090, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:11:40.627 1: SolCast DEBUG&amp;gt; Epoche 3500: Train MSE=0.000184, Val MSE=0.000338, Val MAE=0.014317, Val MedAE=0.012038, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:11:56.504 1: SolCast DEBUG&amp;gt; Epoche 3600: Train MSE=0.000184, Val MSE=0.000338, Val MAE=0.014292, Val MedAE=0.011860, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:12:13.062 1: SolCast DEBUG&amp;gt; Epoche 3700: Train MSE=0.000184, Val MSE=0.000318, Val MAE=0.013443, Val MedAE=0.010655, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:12:28.812 1: SolCast DEBUG&amp;gt; Epoche 3800: Train MSE=0.000184, Val MSE=0.000314, Val MAE=0.013299, Val MedAE=0.010337, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:12:44.335 1: SolCast DEBUG&amp;gt; Epoche 3900: Train MSE=0.000184, Val MSE=0.000316, Val MAE=0.013177, Val MedAE=0.009737, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:12:59.748 1: SolCast DEBUG&amp;gt; Epoche 4000: Train MSE=0.000184, Val MSE=0.000344, Val MAE=0.014781, Val MedAE=0.012876, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:13:16.661 1: SolCast DEBUG&amp;gt; Epoche 4100: Train MSE=0.000184, Val MSE=0.000307, Val MAE=0.013173, Val MedAE=0.010441, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:13:31.964 1: SolCast DEBUG&amp;gt; Epoche 4200: Train MSE=0.000184, Val MSE=0.000338, Val MAE=0.013368, Val MedAE=0.008535, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:13:31.971 1: SolCast DEBUG&amp;gt; Epoche 4200: Train MSE=0.000173, Val MSE=0.000338, Val MAE=0.013368, Val MedAE=0.008535, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:13:47.873 1: SolCast DEBUG&amp;gt; Epoche 4300: Train MSE=0.000173, Val MSE=0.000322, Val MAE=0.014152, Val MedAE=0.012068, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:14:02.737 1: SolCast DEBUG&amp;gt; Epoche 4400: Train MSE=0.000173, Val MSE=0.000317, Val MAE=0.013926, Val MedAE=0.011788, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:14:18.079 1: SolCast DEBUG&amp;gt; Epoche 4500: Train MSE=0.000173, Val MSE=0.000301, Val MAE=0.013120, Val MedAE=0.010500, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:14:34.780 1: SolCast DEBUG&amp;gt; Epoche 4600: Train MSE=0.000173, Val MSE=0.000300, Val MAE=0.013251, Val MedAE=0.011131, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:14:50.749 1: SolCast DEBUG&amp;gt; Epoche 4700: Train MSE=0.000173, Val MSE=0.000316, Val MAE=0.013979, Val MedAE=0.011920, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:15:07.488 1: SolCast DEBUG&amp;gt; Epoche 4800: Train MSE=0.000173, Val MSE=0.000298, Val MAE=0.013297, Val MedAE=0.011209, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:15:24.075 1: SolCast DEBUG&amp;gt; Epoche 4900: Train MSE=0.000173, Val MSE=0.000299, Val MAE=0.013338, Val MedAE=0.011219, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:15:40.613 1: SolCast DEBUG&amp;gt; Epoche 5000: Train MSE=0.000173, Val MSE=0.000301, Val MAE=0.012879, Val MedAE=0.009926, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:15:57.651 1: SolCast DEBUG&amp;gt; Epoche 5100: Train MSE=0.000173, Val MSE=0.000296, Val MAE=0.013288, Val MedAE=0.011301, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:16:13.287 1: SolCast DEBUG&amp;gt; Epoche 5200: Train MSE=0.000173, Val MSE=0.000299, Val MAE=0.013429, Val MedAE=0.011297, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:16:29.416 1: SolCast DEBUG&amp;gt; Epoche 5300: Train MSE=0.000173, Val MSE=0.000326, Val MAE=0.014362, Val MedAE=0.012558, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:16:52.624 1: SolCast DEBUG&amp;gt; Epoche 5400: Train MSE=0.000173, Val MSE=0.000293, Val MAE=0.013008, Val MedAE=0.010932, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:17:15.448 1: SolCast DEBUG&amp;gt; Epoche 5500: Train MSE=0.000173, Val MSE=0.000303, Val MAE=0.013566, Val MedAE=0.011497, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:17:36.891 1: SolCast DEBUG&amp;gt; Epoche 5600: Train MSE=0.000173, Val MSE=0.000290, Val MAE=0.012844, Val MedAE=0.010516, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:17:59.157 1: SolCast DEBUG&amp;gt; Epoche 5700: Train MSE=0.000173, Val MSE=0.000301, Val MAE=0.013589, Val MedAE=0.011589, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:18:20.531 1: SolCast DEBUG&amp;gt; Epoche 5800: Train MSE=0.000173, Val MSE=0.000289, Val MAE=0.012913, Val MedAE=0.010712, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:18:35.740 1: SolCast DEBUG&amp;gt; Epoche 5900: Train MSE=0.000173, Val MSE=0.000291, Val MAE=0.013056, Val MedAE=0.010867, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:18:51.160 1: SolCast DEBUG&amp;gt; Epoche 6000: Train MSE=0.000173, Val MSE=0.000305, Val MAE=0.013648, Val MedAE=0.011687, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:19:08.256 1: SolCast DEBUG&amp;gt; Epoche 6100: Train MSE=0.000173, Val MSE=0.000290, Val MAE=0.012878, Val MedAE=0.010646, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:19:23.867 1: SolCast DEBUG&amp;gt; Epoche 6200: Train MSE=0.000173, Val MSE=0.000289, Val MAE=0.012900, Val MedAE=0.010677, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:19:23.869 1: SolCast DEBUG&amp;gt; Early stopping bei Epoche 6200 (no improvement since 2000 epochs)&lt;br /&gt;
2026.01.01 19:19:23.871 1: === Snapshot-Statistik ===&lt;br /&gt;
2026.01.01 19:19:23.873 1: Metric-Improvement Snapshots: 47 (letzte Epoche: 4200)&lt;br /&gt;
2026.01.01 19:19:23.875 1: Bit-Improvement Snapshots:    3 (letzte Epoche: 167)&lt;br /&gt;
2026.01.01 19:19:23.877 1: Bit-Tradeoff Snapshots:       0 (letzte Epoche: 0)&lt;br /&gt;
2026.01.01 19:19:23.884 1: SolCast DEBUG&amp;gt; Best Snapshot reloaded from Epoche 4200: Train MSE=0.000173, Val MSE=0.000338, Val MAE=0.013368, Val MedAE=0.008535, Bit_Fail=0,&lt;br /&gt;
2026.01.01 19:19:23.886 1: SolCast DEBUG&amp;gt; Run Validation Test with 20% of Input data ...&lt;br /&gt;
2026.01.01 19:19:23.930 1: SolCast DEBUG&amp;gt; Validation finished - Best Training MSE=0.000173, Validation MSE=0.000338, Validation Bit_Fail=0&lt;br /&gt;
2026.01.01 19:19:23.933 1: SolCast DEBUG&amp;gt; Retrain check -&amp;gt; &lt;br /&gt;
-- In Normalization Space: -- &lt;br /&gt;
Train MSE=0.000173 &lt;br /&gt;
Val MSE=0.000338 &lt;br /&gt;
Val Mean=0.0002966460 &lt;br /&gt;
VAL/TRAIN MSE Ratio=1.953186 (limit=2.5) &lt;br /&gt;
Diff=0.000165 (limit=0.005) &lt;br /&gt;
ValStd=0.0000123896 (limit=7.41615117947988e-05) &lt;br /&gt;
-- At Original Scale: -- &lt;br /&gt;
MAE=220.184381409254 &lt;br /&gt;
RMSE/MAE=1.3759 (limit=1.5) &lt;br /&gt;
Slope=0.914758 (limit=0.7 .. 1.3) &lt;br /&gt;
Bias=-38.97 (limit=+-110.092190704627) &lt;br /&gt;
R2=0.880327221041415 &lt;br /&gt;
P95=605.3179 (limit=880.737525637016) &lt;br /&gt;
P99=868.5353 (limit=1761.47505127403) &lt;br /&gt;
-- Robustness Indicators: -- &lt;br /&gt;
RMSE relative=65 (limit=20) &lt;br /&gt;
BitFail=0 (limit=5) &lt;br /&gt;
BitFailRate=0.0000 (limit=0.1) &lt;br /&gt;
-&amp;gt; Retrain&lt;br /&gt;
2026.01.01 19:19:23.945 1: SolCast DEBUG&amp;gt; Best model after retries comes from Attempt=3 with: &lt;br /&gt;
Seed=16689959, &lt;br /&gt;
Model Slope=0.91, &lt;br /&gt;
Model Bias=-38.97, &lt;br /&gt;
VAL MedAE=140.59, &lt;br /&gt;
VAL MAE=220.18, &lt;br /&gt;
VAL RMSE=302.94, &lt;br /&gt;
VAL RMSE relative=65 %, &lt;br /&gt;
VAL RMSE_Rating=very bad, &lt;br /&gt;
VAL R2=0.88, &lt;br /&gt;
Val MSE=0.000338&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Auswertung der Trainingskennwerte ====&lt;br /&gt;
&lt;br /&gt;
Abrufbar über:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get &amp;lt;Name&amp;gt; valDecTree aiNeuralNetConState&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Modellparameter ===== &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Kennwert !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| Normierungsgrenzen || Skalierung der Eingabedaten&lt;br /&gt;
|-&lt;br /&gt;
| Trainingsdaten || Anzahl der Datensätze (Training/Validierung)&lt;br /&gt;
|-&lt;br /&gt;
| Architektur || Inputs, Hidden Layers, Outputs&lt;br /&gt;
|-&lt;br /&gt;
| Hyperparameter || Learning Rate, Momentum, BitFail‑Limit&lt;br /&gt;
|-&lt;br /&gt;
| Aktivierungen || Hidden/Output‑Aktivierungsfunktionen&lt;br /&gt;
|-&lt;br /&gt;
| Zufallsgenerator || Shuffle‑Mode und Shuffle‑Periode&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Trainingsmetriken ===== &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Kennwert !! Interpretation&lt;br /&gt;
|-&lt;br /&gt;
| bestes Modell bei Epoche || Zeitpunkt minimalen Validierungsfehlers&lt;br /&gt;
|-&lt;br /&gt;
| Training MSE / Validation MSE || Fehlermaße; sollten niedrig und ähnlich sein&lt;br /&gt;
|-&lt;br /&gt;
| Validation Bit_Fail || Anzahl fehlerhafter Klassifikationen&lt;br /&gt;
|-&lt;br /&gt;
| bester Trainingslauf || Lauf mit bestem Ergebnis&lt;br /&gt;
|-&lt;br /&gt;
| Trainingsbewertung || Qualitätsindikator (Varianz, Mittelwert)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Fehlermaße der Prognosen ===== &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Kennwert !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| MAE || mittlerer absoluter Fehler (Wh)&lt;br /&gt;
|-&lt;br /&gt;
| MedAE || medianer Fehler&lt;br /&gt;
|-&lt;br /&gt;
| RMSE || quadratischer Fehler, betont Ausreißer&lt;br /&gt;
|-&lt;br /&gt;
| MAPE || prozentualer Fehler&lt;br /&gt;
|-&lt;br /&gt;
| MdAPE || medianer prozentualer Fehler&lt;br /&gt;
|-&lt;br /&gt;
| R² || Gütemaß (0–1)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Interpretation des Beispielmodells ===== &lt;br /&gt;
&lt;br /&gt;
Die Modellkennzahlen können nach ausgführten Training mit&lt;br /&gt;
&lt;br /&gt;
 get &amp;lt;Name&amp;gt; valDecTree aiNeuralNetConState&lt;br /&gt;
&lt;br /&gt;
angezeigt werden. Eine Beispielausgabe sieht etwa so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
letztes KI-Training: 25.12.2025 03:52:41 / Laufzeit in Sekunden: 1951&lt;br /&gt;
letzte KI-Ergebnis Generierungsdauer: 20.37 ms&lt;br /&gt;
&lt;br /&gt;
=== Modellparameter ===&lt;br /&gt;
&lt;br /&gt;
Normierungsgrenzen: PV=9276 W, Hausverbrauch: Min=0 W / Max=8937 W&lt;br /&gt;
Trainingsdaten: 7760 Datensätze (Training=6208, Validierung=1552)&lt;br /&gt;
Architektur: Inputs=41, Hidden Layers=80-40-20, Outputs=1&lt;br /&gt;
Hyperparameter: Learning Rate=0.005, Momentum=0.5, BitFail-Limit=0.35&lt;br /&gt;
Aktivierungen: Hidden=SIGMOID, Steilheit=0.9, Output=LINEAR&lt;br /&gt;
Zufallsgenerator: Mode=2, Periode=10&lt;br /&gt;
&lt;br /&gt;
=== Trainingsmetriken ===&lt;br /&gt;
&lt;br /&gt;
bestes Modell bei Epoche: 8690 (von max. 15000)&lt;br /&gt;
Training MSE: 0.000&lt;br /&gt;
Validation MSE: 0.000&lt;br /&gt;
Validation Bit_Fail: 0&lt;br /&gt;
bester Trainingslauf: 2&lt;br /&gt;
Trainingsbewertung: ok (Val MSE Standard Deviation=0.000000, Val MSE Avg=0.000003)&lt;br /&gt;
&lt;br /&gt;
=== Fehlermaße der Prognosen ===&lt;br /&gt;
&lt;br /&gt;
MAE: 122.74 Wh&lt;br /&gt;
MedAE: 69.28 Wh&lt;br /&gt;
RMSE: 0.002&lt;br /&gt;
MAPE: 17.526 %&lt;br /&gt;
MdAPE: 10.611 %&lt;br /&gt;
R²: 0.847&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Interpretation dieser Daten wird im angezeigten Popup mit ausgegeben und ist diesem Fall:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 7760 Datensätze → sehr gute Basis  &lt;br /&gt;
* 80‑40‑20 Architektur → geeignet für komplexe Muster  &lt;br /&gt;
* MSE ≈ 0 → exzellente Modellanpassung  &lt;br /&gt;
* MAE 122 Wh → sehr präzise  &lt;br /&gt;
* R² = 0.847 → hohe Erklärungsqualität  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Modell ist stabil, generalisiert gut und liefert sehr brauchbare Prognosen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== DriftSlope – Bedeutung, Berechnung und Interpretation ====&lt;br /&gt;
🧩 &#039;&#039;&#039;Was ist DriftSlope?&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DriftSlope&#039;&#039;&#039; beschreibt, wie stark sich die Dynamik des Modells im Vergleich zur Realität verändert hat. &amp;lt;br&amp;gt;&lt;br /&gt;
Dynamik bedeutet hier: &#039;&#039;&#039;Wie stark steigen oder fallen die Werte im Verhältnis zueinander?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ein Modell kann also:&lt;br /&gt;
* &#039;&#039;&#039;zu flach&#039;&#039;&#039; sein (reagiert zu wenig auf Veränderungen),&lt;br /&gt;
* &#039;&#039;&#039;zu steil&#039;&#039;&#039; sein (überreagiert),&lt;br /&gt;
* oder &#039;&#039;&#039;perfekt&#039;&#039;&#039; zur Realität passen.&lt;br /&gt;
&lt;br /&gt;
DriftSlope misst genau diese Abweichung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🧮 &#039;&#039;&#039;Wie wird DriftSlope berechnet?&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
[[Datei:DriftSlope.png|right|thumb|400px|DriftSlope]]&lt;br /&gt;
&lt;br /&gt;
Die Formel lautet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DriftSlope = SlopeLive / SlopeModel&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SlopeLive&#039;&#039;&#039; = Steigung aus den letzten Live‑Daten&lt;br /&gt;
* &#039;&#039;&#039;SlopeModel&#039;&#039;&#039; = Steigung aus dem ursprünglichen Modelltraining&lt;br /&gt;
&lt;br /&gt;
Damit ist DriftSlope ein &#039;&#039;&#039;Verhältnis&#039;&#039;&#039;, kein Unterschied.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🎯 &#039;&#039;&#039;Warum ist das ein Verhältnis und keine Differenz?&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Verhältnis ist robust gegenüber Skalierung und Lastniveau. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beispiel:&#039;&#039;&#039;&lt;br /&gt;
* Modell: Slope = 0.9 / Live: Slope = 0.9 → Verhältnis = 1.0 → &#039;&#039;&#039;perfekt&#039;&#039;&#039;&lt;br /&gt;
* Modell: 0.9 / Live: 0.45 → Verhältnis = 0.5 → &#039;&#039;&#039;Modell ist doppelt so steil wie die Realität&#039;&#039;&#039;&lt;br /&gt;
* Modell: 0.9 / Live: 1.35 → Verhältnis = 1.5 → &#039;&#039;&#039;Modell ist zu flach&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Differenz (z. B. 0.9 − 0.45 = 0.45) wäre nicht interpretierbar, weil sie nicht skaliert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
📊 &#039;&#039;&#039;Wie interpretiert man DriftSlope?&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! DriftSlope !! Bedeutung !! Interpretation&lt;br /&gt;
|-&lt;br /&gt;
| ≈ 1.0 || perfekt || Modell und Realität haben die gleiche Dynamik&lt;br /&gt;
|-&lt;br /&gt;
| 0.85 - 1.15 || leichte Abweichung || Modell ist etwas flacher oder steiler&lt;br /&gt;
|-&lt;br /&gt;
| 0.70 - 1.30 || moderate Drift || Modell reagiert spürbar anders als die Realität&lt;br /&gt;
|-&lt;br /&gt;
|  || starke Drift || Modell ist deutlich zu flach oder zu steil&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🧭 &#039;&#039;&#039;Warum ist die Richtung wichtig?&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* DriftSlope &amp;gt; 1.0  &lt;br /&gt;
::→ Live‑Dynamik ist stärker&lt;br /&gt;
::→ Modell reagiert zu wenig&lt;br /&gt;
::→ Prognosen müssen verstärkt werden&lt;br /&gt;
&lt;br /&gt;
* DriftSlope &amp;lt; 1.0  &lt;br /&gt;
::→ Live‑Dynamik ist schwächer&lt;br /&gt;
::→ Modell reagiert zu stark&lt;br /&gt;
::→ Prognosen müssen abgeschwächt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Damit steuert DriftSlope die &#039;&#039;&#039;multiplikative Korrektur&#039;&#039;&#039; des Modells.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🧠 &#039;&#039;&#039;Zusammenfassung&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DriftSlope&#039;&#039;&#039; ist ein Verhältnis:&lt;br /&gt;
&lt;br /&gt;
 DriftSlope = SlopeLive / SlopeModel&lt;br /&gt;
&lt;br /&gt;
Es zeigt:&lt;br /&gt;
* wie gut das Modell die reale Dynamik abbildet&lt;br /&gt;
* ob das Modell zu flach oder zu steil ist&lt;br /&gt;
* wie stark die Drift ist&lt;br /&gt;
* wie stark die Korrektur ausfallen soll&lt;br /&gt;
&lt;br /&gt;
DriftSlope ist damit ein zentraler Baustein der Drift‑Erkennung und der automatischen Modellkorrektur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== automatische Bias‑ und Drift‑Korrektur (Überblick) ====&lt;br /&gt;
&lt;br /&gt;
📘 Die Verbrauchs‑Prognose nutzt ein neuronales Netz, das aus historischen Verbrauchsdaten lernt. Damit die Vorhersagen auch bei veränderten Haushaltsmustern stabil und realistisch bleiben, wird das Roh‑Ergebnis des Modells bei jeder Prognoseerstellung durch zwei zusätzliche Korrekturschritte verbessert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== 🔧 1. Modell‑Bias‑Korrektur (Feinabstimmung) =====&lt;br /&gt;
&lt;br /&gt;
Das neuronale Netz kann nach dem Training einen kleinen systematischen Fehler haben – zum Beispiel leicht zu hoch oder zu niedrig liegen. Dieser Fehler wird als &amp;lt;code&amp;gt;ModelBias&amp;lt;/code&amp;gt; gemessen.&lt;br /&gt;
&lt;br /&gt;
Die Bias‑Korrektur:&lt;br /&gt;
&lt;br /&gt;
* wirkt nur im Grundlastbereich (keine Peak‑Verzerrung)&lt;br /&gt;
* ist additiv – korrigiert wird aber nicht um einen festen Wert, sondern um einen &#039;&#039;&#039;Anteil&#039;&#039;&#039; des gemessenen Bias, der von der Modellgüte abhängt&lt;br /&gt;
* wird über eine Zonenlogik gesteuert:&lt;br /&gt;
** Zone 1 (grün): Modell ist sehr stabil → 70 % des Bias werden korrigiert&lt;br /&gt;
** Zone 2 (gelb): Modell ist moderat stabil → 50 % des Bias werden korrigiert&lt;br /&gt;
** Zone 2b (nur bei bestimmten Haushaltsprofilen): 25 % des Bias werden korrigiert&lt;br /&gt;
** Zone 3 (rot): Modellqualität reicht nicht aus → keine additive Korrektur&lt;br /&gt;
&lt;br /&gt;
Damit wird das Modell feinjustiert, ohne Peaks oder Lastspitzen zu verändern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== 🌡️ 2. Drift‑Korrektur (Anpassung an aktuelles Verbrauchsverhalten) ===== &lt;br /&gt;
&lt;br /&gt;
Der Verbrauch eines Haushalts kann sich im Laufe der Zeit ändern (z. B. neue Geräte, anderes Verhalten, Jahreszeit). Die Drift‑Analyse erkennt solche Veränderungen anhand von:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftSlope&amp;lt;/code&amp;gt; – Verhältnis zwischen aktueller und zuletzt kalibrierter Regressionssteigung&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftRmseRelRatio&amp;lt;/code&amp;gt; – Verhältnis der aktuellen relativen Fehlerlage (RMSE) zur Referenz&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftBias&amp;lt;/code&amp;gt; – aktuelle systematische Verschiebung gegenüber der Referenz&lt;br /&gt;
&lt;br /&gt;
Wenn Drift erkannt wird, wird die Prognose angepasst:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;✔ Level‑Korrektur&#039;&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
Die Vorhersage wird proportional verstärkt oder abgeschwächt, je nachdem wie stark sich das aktuelle Verbrauchsniveau von der zuletzt kalibrierten Referenz unterscheidet.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;✔ Drift‑Bias&#039;&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
Ein zusätzlicher Korrekturwert wird – ebenfalls nur im Grundlastbereich – addiert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;✔ Adaptive Drift‑Gewichtung&#039;&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
Die Stärke der Drift‑Korrektur hängt dynamisch ab von:&lt;br /&gt;
* Abweichung des Slopes von der Referenz&lt;br /&gt;
* Stärke der relativen Fehlerabweichung (RMSE)&lt;br /&gt;
* allgemeiner Modellqualität (MAE)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;✔ Drift‑Zonenlogik&#039;&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
Zusätzlich wird die Drift in drei Stufen eingeteilt:&lt;br /&gt;
* Drift‑Grün: kaum Drift → nur 10 % der Level‑Korrektur wirksam&lt;br /&gt;
* Drift‑Gelb: moderater Drift → 40 % der Level‑Korrektur wirksam&lt;br /&gt;
* Drift‑Rot: starker Drift → 70 % der Level‑Korrektur wirksam&lt;br /&gt;
&lt;br /&gt;
Damit reagiert die Prognose sanft bei kleinen Veränderungen und stärker bei echten Strukturbrüchen. &#039;&#039;&#039;Nachts (00–06 Uhr)&#039;&#039;&#039; sowie bei einem frisch trainierten Modell wird die Drift‑Level‑Korrektur automatisch deaktiviert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🎯 &#039;&#039;&#039;Warum das wichtig ist&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
Ohne Bias‑ und Drift‑Korrektur würden Prognosen:&lt;br /&gt;
* bei veränderten Verbrauchsgewohnheiten zu hoch oder zu niedrig liegen&lt;br /&gt;
* Peaks falsch einschätzen&lt;br /&gt;
* langsam oder gar nicht auf neue Muster reagieren&lt;br /&gt;
&lt;br /&gt;
Mit der Korrektur:&lt;br /&gt;
* bleibt die Prognose realistisch und stabil&lt;br /&gt;
* passt sich automatisch an das aktuelle Verhalten an&lt;br /&gt;
* schützt Peaks vor Überkorrektur&lt;br /&gt;
* liefert visuell plausible Verläufe&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== 🔄 3. Rekalibrierung nach einem neuen Training (Drift‑Reset) ===== &lt;br /&gt;
&lt;br /&gt;
Nach jedem KI‑Training startet das Modell mit einem neutralen Drift‑Zustand. Das ist wichtig, weil die Drift‑Analyse auf einem Zeitfenster der jüngsten Vergangenheit basiert (standardmäßig 96 Stunden, je nach Situation automatisch zwischen 48 und 144 Stunden angepasst) – unmittelbar nach dem Training stammen diese Daten aber noch vom alten Modell.&lt;br /&gt;
&lt;br /&gt;
Damit keine falsche Drift entsteht, wird die Drift‑Pipeline automatisch zurückgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftBias&amp;lt;/code&amp;gt; wird auf 0.0 gesetzt&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftSlope&amp;lt;/code&amp;gt; wird auf 1.0 gesetzt&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftFlag&amp;lt;/code&amp;gt; wird auf &amp;lt;code&amp;gt;fresh_model&amp;lt;/code&amp;gt; gesetzt&lt;br /&gt;
* die übrigen Drift‑Kennzahlen (u. a. &amp;lt;code&amp;gt;DriftScore&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DriftRmseRelRatio&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DriftIndex&amp;lt;/code&amp;gt;) werden gelöscht und im UI als „‑&amp;quot; angezeigt, bis wieder ausreichend Live‑Daten vorliegen&lt;br /&gt;
* die Referenzwerte für die Korrektur (&amp;lt;code&amp;gt;DriftRefBias&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DriftRefSlope&amp;lt;/code&amp;gt;) werden auf die Werte aus dem aktuellen Training gesetzt&lt;br /&gt;
&lt;br /&gt;
Erkennt das System über mehrere Stunden hinweg &#039;&#039;&#039;anhaltende und plausible&#039;&#039;&#039; Drift, werden die Korrektur‑Referenzwerte sanft an die realen Verbrauchsdaten angepasst:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftRefBias&amp;lt;/code&amp;gt; ersetzt den bisherigen Referenzwert als neue Basislinie für die additive Korrektur. → Das Modell verschiebt sein Grundniveau, damit die Vorhersage im Mittel wieder stimmt.&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftRefSlope&amp;lt;/code&amp;gt; ersetzt den bisherigen Referenzwert als neue Basis für die Level‑Korrektur. → Das Modell reagiert wieder angemessen auf Verbrauchsänderungen.&lt;br /&gt;
* Die ursprünglichen Trainingswerte &amp;lt;code&amp;gt;ModelBias&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;ModelSlope&amp;lt;/code&amp;gt; bleiben davon unberührt als Referenz erhalten.&lt;br /&gt;
&lt;br /&gt;
Diese Rekalibrierung geschieht bewusst nur in kleinen, gedämpften Schritten (nie ein voller Sprung auf die Live‑Werte) und &#039;&#039;&#039;erst, wenn eine Sicherheitsprüfung sie zulässt&#039;&#039;&#039; – siehe nächster Abschnitt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== 🛡️ Schutz vor Fehlalarmen ===== &lt;br /&gt;
&lt;br /&gt;
Bevor eine Rekalibrierung tatsächlich durchgeführt wird, prüft das System die aktuelle Datenlage auf Plausibilität. Erkannt und &#039;&#039;&#039;blockiert&#039;&#039;&#039; werden unter anderem:&lt;br /&gt;
&lt;br /&gt;
* typische Nacht‑/Grundlastphasen (keine echte Drift, nur niedriger Verbrauch)&lt;br /&gt;
* unplausible oder stark schwankende Slope‑/Bias‑Werte (Hinweis auf Sensor‑ oder API‑Fehler statt echter Verhaltensänderung)&lt;br /&gt;
* Fälle, in denen das Modell zwar generell ungenau, aber &#039;&#039;&#039;nicht driftend&#039;&#039;&#039; ist (hier hilft ein Retraining mehr als eine Rekalibrierung)&lt;br /&gt;
&lt;br /&gt;
Nur wenn keiner dieser Fälle vorliegt, wird tatsächlich rekalibriert. Bleibt die Drift trotzdem über viele Stunden bestehen, meldet das System stattdessen eine Retraining‑Empfehlung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== ⏳ 4. Drift‑Sperrmechanismus (ModelAgeHours) ===== &lt;br /&gt;
&lt;br /&gt;
Damit die Drift‑Analyse nur auf echten Live‑Daten des neuen Modells basiert, wird sie erst aktiviert, wenn genügend neue Daten vorliegen.&lt;br /&gt;
&lt;br /&gt;
Das Modellalter wird automatisch berechnet:&lt;br /&gt;
* aus dem Zeitstempel des letzten Trainings&lt;br /&gt;
* und dem Zeitindex der neuesten Verbrauchsdaten&lt;br /&gt;
&lt;br /&gt;
Solange das Modell jünger als die konfigurierte Mindestreife (aktuell 6 Stunden) ist:&lt;br /&gt;
* wird keine Drift berechnet&lt;br /&gt;
* alle Drift‑Parameter bleiben neutral&lt;br /&gt;
* die Prognose nutzt nur das neuronale Netz und die Modell‑Bias‑Korrektur&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftFlag = fresh_model&amp;lt;/code&amp;gt;&lt;br /&gt;
* Drift‑Kennzahlen werden im UI als „‑&amp;quot; angezeigt&lt;br /&gt;
&lt;br /&gt;
Nach Ablauf dieser Mindestzeit wird die Drift‑Analyse automatisch freigeschaltet.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🎯 &#039;&#039;&#039;Warum diese Mechanismen wichtig sind&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ohne Rekalibrierung, Sicherheitsprüfung und Sperrmechanismus würden:&lt;br /&gt;
* direkt nach dem Training falsche Drift‑Signale entstehen&lt;br /&gt;
* die Prognose durch alte Fehlerbilder verzerrt&lt;br /&gt;
* Bias‑ und Drift‑Korrektur in die falsche Richtung wirken&lt;br /&gt;
* severe‑Drift‑Alarme auftreten, obwohl das Modell frisch ist – oder obwohl nur ein Sensor gerade falsche Werte liefert&lt;br /&gt;
&lt;br /&gt;
Mit dieser Logik:&lt;br /&gt;
* startet jedes Modell neutral und stabil&lt;br /&gt;
* Drift wird erst aktiv, wenn genügend neue Live‑Daten existieren&lt;br /&gt;
* offensichtlich unplausible Datenlagen lösen keine Rekalibrierung aus&lt;br /&gt;
* die Prognose bleibt ruhig, plausibel und robust&lt;br /&gt;
* Fehlalarme werden deutlich reduziert&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&#039;&#039;Eine ausführliche, technische Beschreibung mit allen Formeln, Zonenschwellen und der zugrunde liegenden ML‑Theorie findet sich im Deep‑Dive‑Artikel: [[Driftmanagement und Bias-Korrektur im SolarForecast KI-Prognosesystem]]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Modulinterne Datenstrukturen ==&lt;br /&gt;
Das Modul speichert die verschiedenen historischen und aktuellen Daten wie PV-Prognose, Witterungsdaten (Regen, Bewölkung), Strahlungsdaten, Einspeisung, Bezug, reale Erzeugungsdaten und vieles mehr zur Laufzeit im Arbeitsspeicher. Dadurch ist die Verarbeitung dieser Daten im Vergleich zu Lesevorgängen aus dem Filesystem bzw. einer Datenbank sehr performant. Allerdings würden diese Daten bei einem FHEM Absturz bzw. bei einem regulären Shutdown verlorengehen.&lt;br /&gt;
&lt;br /&gt;
Deswegen werden die relevanten Daten regelmäßig in Dateien gesichert und bei Bedarf wiederhergestellt. Diese Dateien befinden sich im Verzeichnis &#039;&#039;&#039;../fhem/FHEM/FhemUtils&#039;&#039;&#039; und heißen &#039;&#039;&#039;.*_SolarForecast_.*&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Die Daten werden in jedem Zyklus der Zentralschleife (CentralTask) gesammelt bzw. berechnet. Der Zyklus wird mit dem Attribut &#039;&#039;&#039;plantControl-&amp;gt;cycleInterval&#039;&#039;&#039; eingestellt.&lt;br /&gt;
&lt;br /&gt;
Zur Laufzeit können diese Daten über get-Kommandos abgerufen werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get ... pvHistory [Tag]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der pvHistory Datenspeicher enthält die vergangenen Kennwerte der letzten 31 Tage mit einer Genauigkeit von einer Stunde. Es werden die Prognosewerte für Erzeugung und Verbrauch, die realen Werte für Erzeugung und Verbrauch sowie ebenso die Laufzeiten jedes einzelnen Verbrauchers (Consumer) festgehalten. Für jeden Tag gibt es die Stunde &amp;quot;99&amp;quot; die eine Summierung der Stundenwerte des Tages bzw. Sonderschlüssel enthält.&lt;br /&gt;
&lt;br /&gt;
Bei Bedarf lässt sich mit dem Befehl &amp;quot;set ... reset pvHistory&amp;quot; der gesamte Inhalt des Speichers löschen (nicht empfohlen). Selektiver funktioniert die Datenlöschung mit &amp;quot;set ... reset pvHistory &amp;lt;Tag&amp;gt;&amp;quot; (Daten eines bestimmten Tages löschen) bzw. &amp;quot;set ... reset pvHistory &amp;lt;Tag&amp;gt; &amp;lt;Stunde&amp;gt;&amp;quot; (Daten der Stunde  eines bestimmten Tages löschen). Die letzten beiden Kommandos müssen über die Kommandozeile im Browser ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get ... pvCircular &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Ringspeicher enthält Daten der letzten 24 Stunden sowie fortwährend berechnete Werte wie Korrekturfaktoren der PV-Erzeugung und Prognosequalität.&lt;br /&gt;
Neue Stundenwerte des Tages überschreiben die gespeicherten Schüssel des vorangegangenen Tages sofern es sich nicht um fortwährend berechnete Werte handelt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get ... nextHours&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Speicher enthält sämtliche Prognosewerte der kommenden Stunden beginnend mit der aktuellen Stunde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get ... radiationApiData&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Abhängig von der ausgewählten Strahlungsdaten API enthält dieser Speicher die von der API gelieferten Rohdaten sowie evtl. weitere für die Funktion benötigte Daten wie API-Keys, Response Messages, Anzahl der API Abruf und weitere.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get ... valCurrent&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Struktur wird nicht regelmäßig im Filesystem gespeichert und enthält immer aktuell gesammelte oder berechnete/gelieferte Daten wie z.B. die Autarkierate, letze Laufzeit der Zentralschleife (CentralTask), Zeit des Sonnenauf- und untergangs sowie weitere Betriebsdaten. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get ... valConsumerMaster [XX]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zeigt die Daten der aktuell im SolarForecast Device registrierten Verbraucher. Mit der Nummer &#039;&#039;&#039;XX&#039;&#039;&#039; kann ein bestimmter Verbraucher angesprungen werden. Die Nummer korrespondiert mit dem entsprechenden &#039;&#039;&#039;consumerXX&#039;&#039;&#039; Attribut.&lt;br /&gt;
Neben anderen Betriebs- und Energiedaten werden insbesondere folgende Daten ermittelt, die für die zukünftige Planung der Verbraucherschaltzeiten relevant sind:&lt;br /&gt;
&lt;br /&gt;
* epieces - prognostizierte Energiescheiben pro Betriebsstunde &lt;br /&gt;
&lt;br /&gt;
Ausgehend von gespeicherten historischen Verbrauchsdaten des Verbrauchers wird der Energieverbrauch des Verbrauchers in seiner ersten Betriebsstunde prognostiziert, was insbesondere für die Planung der optimalen Startzeit des Verbrauchers in Bezug zu der prognostizierten PV Energie und den Verbrauchswerten weiterer vorhandener bzw. zu planender Verbraucher Berücksichtigung findet. Weitere Informationen zur Verbrauchersteuerung in diesem  [[#Verbrauchersteuerung_-_Registrieren_und_visualisieren_von_Verbrauchern|Abschnitt]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Schnittstelle für Modulautoren bzw. eigenen Code ===&lt;br /&gt;
&lt;br /&gt;
Die im vorherigen Artikel beschriebenen internen Datenstrukturen können durch externen Code abgefragt und ausgewertet werden.&lt;br /&gt;
Dazu stehen die folgenden Funktionen zur Verfügung. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]BatteryVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;Bn&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... valBattery&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]CurrentVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... valCurrent&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]InverterVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;Nr&amp;gt;&#039;, &amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... valInverter&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]ProducerVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;Nr&amp;gt;&#039;, &amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... valProducer&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]HistoryVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;Day&amp;gt;&#039;, &#039;&amp;lt;HoD&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... pvHistory&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]CircularVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;HoD&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... pvCircular&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]NexthoursVal (&#039;&amp;lt;Name&amp;gt;&#039;, &amp;lt;nhr&amp;gt;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... nextHours&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]ConsumerVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;Nr&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... valConsumerMaster&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]RadiationAPIVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;String&amp;gt;&#039;, &#039;&amp;lt;DateTime&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... radiationApiData&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]WeatherAPIVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;APIname&amp;gt;&#039;, &#039;&amp;lt;TimeCode&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... weatherApiData&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]StatusAPIVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;APIname&amp;gt;&#039;, &#039;&amp;lt;QTag&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... statusApiData&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]StringVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;String&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... valStrings&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Angabe des Packages (FHEM::SolarForecast::) ist nur notwendig wenn die Funktionen von außerhalb des SolarForecast-Devices aufgerufen werden. Innerhalb des Devices (Code-Ausführung im Attribut &#039;&#039;ctrlUserExitFn&#039;&#039;) kann darauf verzichtet werden.&lt;br /&gt;
&lt;br /&gt;
Die Bedeutung der Platzhalter sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     &amp;lt;Name&amp;gt;     - Name des SolarForecast Devices&lt;br /&gt;
     &amp;lt;Day&amp;gt;      - abzufragender Tag (01 - 31)&lt;br /&gt;
     &amp;lt;Bn&amp;gt;       - Batterie Nummer (01, 02, ...)&lt;br /&gt;
     &amp;lt;DateTime&amp;gt; - Startzeit der Form YYYY-MM-DD hh:00:00&lt;br /&gt;
     &amp;lt;TimeCode&amp;gt; - Zeitwert der Form fcX_XX (z.B. fc1_19)&lt;br /&gt;
     &amp;lt;APIname&amp;gt;  - Hauptname der API gemäß setupWeatherDev1 (z.B. OpenMeteo)&lt;br /&gt;
     &amp;lt;String&amp;gt;   - Name des PV-Modulstrings wie im Attribut &#039;setupInverterStrings&#039;&lt;br /&gt;
     &amp;lt;QTag&amp;gt;     - Question Tag, z.B. &#039;?All&#039;&lt;br /&gt;
     &amp;lt;Nr&amp;gt;       - laufende Nummer des Verbrauchers / Gerätes (01, 02, 03, 04,...)&lt;br /&gt;
     &amp;lt;HoD&amp;gt;      - abzufragende Stunde (01 - 24, 99)&lt;br /&gt;
     &amp;lt;nhr&amp;gt;      - nächste Stunde (NextHour00, NextHour01,...)&lt;br /&gt;
     &amp;lt;Key&amp;gt;      - der abzufragende Schlüssel &lt;br /&gt;
     &amp;lt;default&amp;gt;  - def default-Rückgabewert&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Beispiel Auslesen der Batterieladestrategie und Anlegen eines Readings ====&lt;br /&gt;
&lt;br /&gt;
Als Praxisbeispiel soll die aktuelle gesetzte Ladestrategie für Batterie &amp;quot;01&amp;quot; ausgelesen und mit dem Wert ein Reading im SolarForecast Device angelegt werden. &amp;lt;br&amp;gt;&lt;br /&gt;
Dazu wird der folgende Code im Attribut &#039;&#039;ctrlUserExitFn&#039;&#039; hinterlegt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  my $wert = NexthoursVal ($name, &#039;NextHour00&#039;, &#039;strategybat01&#039;, &#039;loadRelease&#039;);&lt;br /&gt;
  storeReading (&#039;Ladestrategie&#039;, $wert);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei jedem Zyklus des SF-Devices wird der aktuelle Wert von &#039;&#039;strategybat01&#039;&#039; gelesen und im Reading &#039;&#039;Ladestrategie&#039;&#039; gespeichert. Die Paket-Definition &#039;&#039;FHEM::SolarForecast::&#039;&#039; braucht nicht verwendet werden, da der Aufruf im Attribut ctrlUserExitFn innerhalb des SolarForecast-Paketes erfolgt.&lt;br /&gt;
&lt;br /&gt;
Für andere Batterienummern ist der NexthoursVal-Schlüssel &#039;&#039;strategybat01&#039;&#039; entsprechend anzupassen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Auswerten von internen Arrays ===&lt;br /&gt;
&lt;br /&gt;
Die meisten der internen Datenstrukturen liefern bei der Abfrage einen einfachen String oder numerischen Wert der ausgewertet werden kann. Es gibt allerdings auch intern gespeicherte Wertelisten. Werden die Listenstrukturen mit den oben beschriebenen Befehlen abgefragt, wird eine Referenz auf die Liste geliefert sofern sie vorhanden ist.&lt;br /&gt;
&lt;br /&gt;
Um auf die Werte einer solchen Liste zuzugreifen, ist am Beispiel des Arrays &#039;&#039;surplusslidereg&#039;&#039; aus dem Current-Speicher (get ... valCurrent) dargestellt: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
my $splref = CurrentVal ($name, &#039;surplusslidereg&#039;, &#039;.&#039;);&lt;br /&gt;
my $spser  = ref $splref eq &#039;ARRAY&#039; ? join &#039; &#039;, @{$splref} : undef;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Variable $spser enthält bei Vorhandensein der Liste einen String, der die Listenelemente von &#039;surplusslidereg&#039; durch Leerzeichen getrennt enthält.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Backup und Wiederherstellung der Moduldaten ==&lt;br /&gt;
Neben der Datenhaltung in den Attributen und Readings des SolarForecast Devices, erzeugt jedes SolarForecast Device Dateien im Verzeichnis  &#039;&#039;&#039;../fhem/FHEM/FhemUtils&#039;&#039;&#039; mit folgenden Inhalten:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Init_SolarForecast_&amp;lt;name&amp;gt;       - initiatiale Daten die vor dem Einlesen weiterer Daten oder Attribute geladen werden &lt;br /&gt;
PVH_SolarForecast_&amp;lt;name&amp;gt;        - PV History&lt;br /&gt;
PVC_SolarForecast_&amp;lt;name&amp;gt;        - PV Circular&lt;br /&gt;
PVCfg_SolarForecast_&amp;lt;name&amp;gt;      - PV Anlagenkonfiguration&lt;br /&gt;
PVCsm_SolarForecast_&amp;lt;name&amp;gt;      - Consumer Status&lt;br /&gt;
ScApi_SolarForecast_&amp;lt;name&amp;gt;      - Strahlungswerte aus verwendeter API&lt;br /&gt;
StatApi_SolarForecast_&amp;lt;name&amp;gt;    - Statusdaten der verwendeten APIs&lt;br /&gt;
WeatherApi_SolarForecast_&amp;lt;name&amp;gt; - Wetterdaten der gewählten Wetter-API (außer DWD-Device)&lt;br /&gt;
AItra_SolarForecast_&amp;lt;name&amp;gt;      - PV-KI Entscheidungsquelle (trainierte Daten)&lt;br /&gt;
AIraw_SolarForecast_&amp;lt;name&amp;gt;      - PV-KI Input Daten = Raw Trainigsdaten&lt;br /&gt;
NeuralNet_SolarForecast_&amp;lt;name&amp;gt;  - Daten des neuronalen Netztes (KI Verbrauchsprognose)&lt;br /&gt;
Messages_SolarForecast_&amp;lt;name&amp;gt;   - Daten des Nachrichten- und Informationssystems&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Je nach Ausprägung und eingesetzten Features des SolarForecast Devices sind alle oder nur ein Teil dieser Dateien vorhanden. Dabei ist &#039;&#039;&#039;&amp;lt;name&amp;gt;&#039;&#039;&#039; der Name des SolarForecast Devices.&lt;br /&gt;
&lt;br /&gt;
Bei einem Filebackup des FHEM-Servers ist darauf zu achten, dass diese Dateien in dem Backup enthalten sind. Der Inhalt der Dateien ist nicht statisch, sondern kann sich dynamisch aktualisieren. Um im Bedarfsfall einen aktuellen Datenstand zu haben, ist mindestens ein tägliches Backup dieser Dateien empfehlenswert. Eventuell auch öfter mit Hilfe einer Versionierung welche z.B. immer die letzten drei Versionen aufbewahrt.&lt;br /&gt;
&lt;br /&gt;
Beim Start von FHEM werden bestimmte Dateien automatisch gelesen und in das SolarForecast Device importiert. &lt;br /&gt;
Der Vorgang ist mit verbose=3 im Log protokolliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
2023.10.02 09:57:07.967 3: SolCast6 - cached data &amp;quot;Initialize&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.967 3: SolCast6 - set init data writeForceType=db before load over data&lt;br /&gt;
2023.10.02 09:57:07.967 3: SolCast6 - cached data &amp;quot;pvHistory&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.969 3: SolCast6 - cached data &amp;quot;pvCircular&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.970 3: SolCast6 - cached data &amp;quot;consumerMaster&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.970 3: SolCast6 - cached data &amp;quot;radiationApiData&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.970 3: SolCast6 - cached data &amp;quot;statusApiData&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.970 3: SolCast6 - cached data &amp;quot;weatherApiData&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.974 3: SolCast6 - cached data &amp;quot;aiTrainedData&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.976 3: SolCast6 - cached data &amp;quot;aiRawData&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.976 3: SolCast6 - cached data &amp;quot;NeuralNetwork&amp;quot; restored for FANN type &#039;con&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Bestimmte Betriebsdaten, wie z.B. die witterungsabhängigen Korrekturfaktoren (circular) oder die KI-Daten (aitrained/airaw), bauen sich über die Zeit immer granularer auf und stellen einen wertvollen Datenbestand dar.&lt;br /&gt;
&lt;br /&gt;
Wird das SolarForecast Device gelöscht und anschließend wieder neu mit dem gleichen Namen definiert, können die bisher verfügbaren Daten sehr einfach wiederhergestellt werden:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 1. definieren des neuen SolarForecast Devices, d.h. ein einfaches &amp;quot;define &amp;lt;Name&amp;gt; SolarForecast&amp;quot;, und sichern der FHEM Konfiguration (der Konfigurationsdialog muß nicht durchgeführt werden)&lt;br /&gt;
* 2. FHEM stoppen&lt;br /&gt;
* 3. wiederherstellen der oben beschriebenen Dateien aus einem Backup in das Verzeichnis ../fhem/FHEM/FhemUtils (Überschreiben evtl. vorhandener Dateien)&lt;br /&gt;
* 4. Anpassen der Dateieigentümer und Berechtigungen: chown fhem:dialout /opt/fhem/FHEM/FhemUtils/*,  chmod 774 /opt/fhem/FHEM/FhemUtils/*&lt;br /&gt;
* 5. starten von FHEM (bestimmte Daten werden automatisch importiert)&lt;br /&gt;
* 6. mit dem Befehl &amp;quot;set &amp;lt;name&amp;gt; plantConfiguration restore&amp;quot; die Anlagenkonfiguration wiederherstellen&lt;br /&gt;
* 7. FHEM Konfiguration sichern und restarten&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Das zuvor beschriebene Verfahren kann auch angewendet werden um das SolarForcast Device von einer FHEM Installation in eine andere Installation umzuziehen. In diesem Fall ist aber besonders darauf zu achten, vorab alle in den SF-Attributen referenzierten Devices wie Inverter, Meter oder DWD-Devices mit den zutreffenden Namen in der neuen Installation anzulegen. Weiterhin muß beachtet werden, dass die &#039;&#039;&#039;Daten nicht zwischen 32 Bit-Systemen und 64 Bit-Systemen ausgetauscht werden können&#039;&#039;&#039;. So können z.B. auf einem 32 Bit-System geschriebene Dateien auf einem 64 Bit-System nicht gelesen werden und vice versa.&lt;br /&gt;
  &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soll das neue SolarForecast Device mit einem anderen Namen oder weitere SolarForecast Devices erstellt werden, welche die Betriebsdaten des primären Devices verwenden sollen, ist wie folgt vorzugehen:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 1. definieren des neuen SolarForecast Devices, d.h. ein einfaches &amp;quot;define &amp;lt;Name&amp;gt; SolarForecast&amp;quot;, und sichern der FHEM Konfiguration (der Konfigurationsdialog muß nicht durchgeführt werden)&lt;br /&gt;
* 2. FHEM stoppen&lt;br /&gt;
* 3. wiederherstellen der oben beschriebenen Dateien aus einem Backup in das Verzeichnis ../fhem/FHEM/FhemUtils (Überschreiben evtl. vorhandener Dateien)&lt;br /&gt;
* 4. umbenenen der Dateien, wobei &amp;lt;name&amp;gt; durch den Namen des neuen SolarForecast Devices ersetzt wird&lt;br /&gt;
* 5. Anpassen der Dateieigentümer und Berechtigungen: chown fhem:dialout /opt/fhem/FHEM/FhemUtils/*,  chmod 774 /opt/fhem/FHEM/FhemUtils/*&lt;br /&gt;
* 6. starten von FHEM (bestimmte Daten werden automatisch importiert)&lt;br /&gt;
* 7. mit dem Befehl &amp;quot;set &amp;lt;name&amp;gt; plantConfiguration restore&amp;quot; die Anlagenkonfiguration wiederherstellen&lt;br /&gt;
* 8. FHEM Konfiguration sichern und restarten&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wenn sich die SolarForecast Devices hinsichtlich ihres Models oder der integrierten Consumer unterscheiden, sind die Dateien &amp;quot;PVCsm_SolarForecast_&amp;lt;name&amp;gt; &amp;quot; , &amp;quot;ScApi_SolarForecast_&amp;lt;name&amp;gt;&amp;quot; von dem Verfahren auszuschließen.&lt;br /&gt;
&lt;br /&gt;
== Batterieintegration und -steuerung ==&lt;br /&gt;
&lt;br /&gt;
=== Wie eine Batterie eingebunden wird ===&lt;br /&gt;
Wie immer muß die Batterieanlage zunächst mit einem für die Batterie spezifischen FHEM-Device in FHEM definiert sein.&lt;br /&gt;
In diesem Device werden Readings erwartet die folgende Werte bereitstellen:&lt;br /&gt;
&lt;br /&gt;
::* ein Reading welches die aktuelle Batterieladeleistung liefert&lt;br /&gt;
&lt;br /&gt;
::* ein Reading welches die aktuelle Batterieentladeleistung liefert&lt;br /&gt;
&lt;br /&gt;
::* ein Reading welches die installierte Batteriekapazität liefert (&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; dieser Schlüssel ist für die Aktivierung des Batterie SOC-Managements und die grafische Anzeige des SOC wesentlich!)&lt;br /&gt;
&lt;br /&gt;
::* ein Reading welches die bis dato vorliegende Lade-Energiemenge als fortlaufenden Zähler liefert (optional)&lt;br /&gt;
&lt;br /&gt;
::* ein Reading welches die bis dato vorliegende Entlade-Energiemenge als fortlaufenden Zähler liefert (optional)&lt;br /&gt;
&lt;br /&gt;
::* Reading welches den aktuellen Ladezustand (SOC in Prozent) liefert (optional)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Batterie, bzw. das Batteriedevice wird mit dem Attribut &#039;&#039;&#039;setupBatteryDev&#039;&#039;&#039; im SolarForecast Device registriert. Die Syntax des Attributes ist in  der Online-Hilfe zum Attribut umfassend erläutert. &lt;br /&gt;
Auch wenn manche Readings optional sind, wird empfohlen alle Werte bereitzustellen um alle Batterie-Funktionen im Modul nutzen zu können. Durch die Weiterentwicklung des Moduls können optionale Readings später auch obligatorisch werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Visualisierung der Batterie in der Balkengrafik ====&lt;br /&gt;
&lt;br /&gt;
Das Attribut &#039;&#039;&#039;setupBatteryDevXX&#039;&#039;&#039; verfügt über den Schlüssel &#039;&#039;&#039;show&#039;&#039;&#039;, mit dem die Einblendung des bzw. der Batteriesymbole in den Ebenen der Balkengrafik gesteuert werden kann:&lt;br /&gt;
[[Datei:Screenshot 2025-02-23 192002.png|right|thumb|400px|Einblendung der Batterieleiste und Darstellung des Batterie-SoC als Balkencontent in der zweiten Ebene]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 0 - keine Anzeige des Gerätes (default)&lt;br /&gt;
* 1 - Anzeige des Gerätes in der Balkengrafik Ebene 1&lt;br /&gt;
* 2 - Anzeige des Gerätes in der Balkengrafik Ebene 2 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Symbole und die Farbgebung der Batterie(n) können mittels des Schlüssels &#039;&#039;&#039;icon&#039;&#039;&#039; verändert werden. Die Online-Hilfe gibt weitere Informationen zur Ausgestaltung. &lt;br /&gt;
&lt;br /&gt;
In der Batteriedarstellung wird das Symbol der aktuellen Stunde hervorgehoben. Ein Mouse-Over zeigt wesentliche Betriebszustände der Batterie. Die Batteriesymbole vergangener Stunden zeigen mit einem Mouse-Over die erreichten SoC (State of Charge) Stände. Die kommenden Stunden visualisieren die folgenden Prognosen:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* der prognostizierte SoC unter Berücksichtigung der PV-Prognose und der [[#Aktivierung_des_Batterie_SOC-Managements|Batteriesteuerung]] sofern sie im Modul aktiviert ist.&lt;br /&gt;
* eine Freigabe bzw. Empfehlung der Batterieladung zur [[#Unterstützung_eines_netzdienlichen_Verhaltens|Unterstützung eines netzdienlichen Verhaltens]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Neben der Einblendung der Batterieleiste über der Balkengrafik selbst können bestimmte Batteriekennwerte als Balkeninhalt dargestellt werden. Die Auswahl erfolgt über das Attribut &#039;&#039;&#039;graphicBeamXContent&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Aktivierung des Batterie SOC- und Lade-Managements ===&lt;br /&gt;
Das integrierte SOC- und Lade-Management verfolgt insbesondere diese Ziele: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* den Ladezustand der Batterie(n) zu optmimieren, was besonders in den Monaten mit geringerer PV-Erzeugung einen wertvollen Beitrag zur Erhöhung der Autarkierate und Batteriepflege leisten kann&lt;br /&gt;
 &lt;br /&gt;
* eine PV-Prognose und Verbrauch optimierte Beladungssteuerung, die in den Monaten mit hoher PV-Erzeugung hilft eine evtl. Abregelung der Anlage zu verhindern, die Batterie ausgewogen über den Tag zu laden und ein netzdienliches Verhalten zu unterstützen&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Aspekte der Batteriesteuerung werden in den folgenden Abschnitten beschrieben. Sind mehrere Batterien installiert, kann die Steuerung getrennt für jede einzelne Batterie aktiviert und eingestellt werden. Dabei ist zu beachten, dass vom Modul nur Signale und Readings bereitgestellt werden, die durch eine entsprechende Routine ausgewertet werden können um spezifische Befehle zur Umsetzung der Steuerung an das Batteriesystem zu senden. &lt;br /&gt;
 &lt;br /&gt;
Für eine Aktivierung des Managements muß zunächst das Batterie-Device wie im vorigen Abschnitt im SolarForecast Device registriert werden.&lt;br /&gt;
Das Attribut &#039;&#039;&#039;ctrlBatSocManagementXX&#039;&#039;&#039; aktiviert die im Modul integrierte SOC- und Lade-Management Routine: &lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Device&amp;gt; ctrlBatSocManagementXX lowSoc=&amp;lt;Wert&amp;gt; upSoC=&amp;lt;Wert&amp;gt; [maxSoC=&amp;lt;Wert&amp;gt;] [careCycle=&amp;lt;Wert&amp;gt;] [loadAbort=&amp;lt;SoC1&amp;gt;:&amp;lt;MinPwr&amp;gt;:&amp;lt;SoC2&amp;gt;] [safetyMargin=&amp;lt;Wert&amp;gt;[:&amp;lt;Wert&amp;gt;]] ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die einzelnen Schlüssel werden der Kalkulationsroutine als Steuerungsparameter übergeben und bedeuten:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;lowSoc:unterer Mindest-SoC, die Batterie wird nicht tiefer als dieser Wert entladen (muß &amp;gt; 0 sein). Dieser Wert kann zum Beispiel dazu dienen, stets eine Mindestenergiemenge für den Fall eines Stromausfalls im öffentlichen Netz in den Batterien vorzuhalten.&lt;br /&gt;
&lt;br /&gt;
;upSoC:oberer Mindest-SoC, Der übliche Wert des optimalen SoC bewegt sich in Perioden mit hohen PV-Überschuß tendenziell zwischen &#039;lowSoC&#039; und &#039;upSoC&#039;, in Perioden mit geringer PV-Ausbeute bzw. geringem PV Energieüberschuß bewegt sich der optimale SoC tendenziell zwischen &#039;upSoC&#039; und &#039;maxSoC&#039;. Die Einstellung von upSoC=50 für ein ausgewogenes Verhalten kann als guter Startwert dienen.&lt;br /&gt;
&lt;br /&gt;
;maxSoC:maximaler Mindest-SoC, d.h. der SoC Wert der mindestens im Abstand von &#039;careCycle&#039; Tagen erreicht werden muß um den Ladungsausgleich im Speicherverbund auszuführen. Die Angabe ist optional (muß &amp;lt;= 100 sein, default: 95)&lt;br /&gt;
&lt;br /&gt;
;stepSoC: Optionale Schrittweite zur optimalen SoC-Berechnung (Battery_OptimumTargetSoC_XX) in %. Mit der Angabe &#039;stepSoC=0&#039; wird das SoC-Management deaktiviert und Battery_OptimumTargetSoC_XX auf den Wert &#039;lowSoC&#039; gesetzt. &#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Die Beziehung &#039;careCycle * stepSoC = 100&#039; sollte eingehalten werden! Wert: 0..5, default: 5 &lt;br /&gt;
&lt;br /&gt;
;careCycle:maximaler Abstand in Tagen, der zwischen zwei Ladungszuständen von mindestens &#039;maxSoC&#039; auftreten sollte. Anders formuliert legt careCycle fest, alle wieviel Tage mindestens einmal maxSoC erreicht werden sollte. Die Angabe ist optional. (default: 20)&lt;br /&gt;
&lt;br /&gt;
;lcSlot: Es wird ein tägliches Zeitfenster festgelegt, in dem die Ladesteuerung des Moduls für diese Batterie aktiv sein soll. Außerhalb des Zeitfensters wird die Batterieladung mit voller Leistung freigegeben. Das SoC-Management der Batterie ist davon nicht betroffen. Wert: &amp;lt;hh:mm&amp;gt;-&amp;lt;hh:mm&amp;gt;, default: ganztägig&lt;br /&gt;
&lt;br /&gt;
;loadAbort: definiert eine vom Anwender gewünnschte Bedingung für einen generellen Ladeabbruch und Wiederfreigabe der Lademöglichkeit. Die Abbruchbedingung ist erfüllt, wenn der angegebene SoC1 (%) erreicht bzw. überschritten ist &#039;&#039;&#039;UND&#039;&#039;&#039; die angegebene Ladeleistung &amp;lt;MinPwr&amp;gt; (W) unterschritten wurde -&amp;gt; Reading Battery_ChargeAbort_XX=1. Fällt der aktuelle SoC wieder unter den SoC2, wird Battery_ChargeAbort_XX=0 gesetzt. Ist SoC2 nicht angegeben, gilt SoC2=SoC1.  &lt;br /&gt;
&lt;br /&gt;
;loadStrategy: Abhängig von der gewählten Ladestrategie wird die Prognose der Batterieladung und ggf. die Generierung der Steuerreadings beeinflusst. Die Angabe ist optional. Wert: loadRelease | optPower | smartPower, default=loadRelease&lt;br /&gt;
	&lt;br /&gt;
;loadTarget: Optionaler Ziel-SoC in % für die Berechnung der Ladefreigabe bzw. der optimalen Ladeleistung. Der Zielwert ist eine kalkulatorische Rechengröße. Der reale SoC kann situativ in Grenzen über- oder unterschritten werden. Der höhere Wert aus Reading Battery_OptimumTargetSoC_XX und &#039;loadTarget&#039; hat für die Berechnung Vorrang. Wert: 0..100, default=100. &amp;lt;br&amp;gt; In loadTarget kann eine Zielzeit angegeben werden, wann der Ziel-SoC erreicht werden soll. Die optimale Ladeleistung wird entsprechend angepasst. Die Zeitangabe als positive Ganzzahl ist ein Absolutwert (Stunde), in der der Ziel-SoC erreicht sein soll. Ein negativer Integer (z.B. -3) besagt, dass drei Stunden vor dem [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Bestimmung_von_Sonnenaufgang_und_Sonnenuntergang|Sonnenuntergang]] des aktuellen Tages der Ziel-SoC erreicht sein soll. D.h. negative Zahlen sind Relativangaben. Generell wird der Ziel-SoC zur Wunschzeit nur dann erreicht sein, wenn genügend PV-Leistung verfügbar ist. &lt;br /&gt;
&lt;br /&gt;
;safetyMargin: Bei der Berechnung der Ladefreigabe und optimierten Ladeleistung werden Sicherheitszuschläge auf den prognostizierten Ladungsbedarf berücksichtigt. Abweichend vom Default können mit diesem Parameter individuelle Sicherheitszuschläge getrennt für die Berechnung der Ladefreigabe und optimierten Ladeleistung angegeben werden. Der erste Wert ist der Zuschlag bei der Berechnung der Ladefreigabe, der zweite Wert der Zuschlag bei der Berechnung der optimierten Ladeleistung. Beide Angaben sind Prozentwerte von 0..100.&lt;br /&gt;
&lt;br /&gt;
;weightOwnUse: Optionale Gewichtung der stündlichen Verbrauchsprognose als zusätzlich verwendbaren Anteil zur Batterieladung in %. Technisch wird der verfügbare PV-Überschuß zur Berechnung der optimierten Ladeleistung erhöht indem der kalkulierte Verbrauch um den angegebenen Prozentsatz gesenkt wird. Wert: 0..100 default: 0 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Alle SoC-Werte sind ganze Zahlen in %. Dabei gilt: &lt;br /&gt;
&lt;br /&gt;
 lowSoc &amp;lt; upSoC &amp;lt; maxSoC&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====  Erläuterung der Batterie-Steuerungsreadings ==== &lt;br /&gt;
&lt;br /&gt;
Für die Steuerung des Batteriesystems gibt es im SolarForecast einen Satz an Readings, die unterschiedliche Zustände signalisieren und für entsprechende Steuerungsaufgaben bezüglich der Batteriesysteme eingesetzt werden können. In den nachfolgenden Abschnitten werden diese Zusammenhänge noch dataillierter beschrieben.&lt;br /&gt;
&lt;br /&gt;
;Hinweis: SolarForecast stellt lediglich Steuerungsinformationen zur Verfügung. Die Umsetzung des Eingriffs in das Batteriesystem erfolgt durch den Anwender selbst über entsprechende Skripte. In den thematischen Abschnitten werden Beispiele für solche Steuerungsskripte vorgestellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Alle erstellten Readings gelten für ein Batteriesystem, es können mehrere Batteriesysteme in SolarForecast integriert sein. Die Endung &#039;&#039;XX&#039;&#039; der Readings beschreibt die Nummer des Batteriesystems und korrespondiert mit der Endung des entsprechenden Attributes &#039;&#039;ctrlBatSocManagementXX&#039;&#039; bzw. &#039;&#039;setupBatteryDevXX&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Battery_OptimumTargetSoC_XX: Mit den im Attribut &#039;&#039;ctrlBatSocManagementXX&#039;&#039; hinterlegten Parametern unter Berücksichtigung von PV- und Verbrauchsprognosen wird ein optimaler SOC-Wert errechnet. Dieser Wert dient zur Einstellung des unteren SOC des Batteriesystems.&lt;br /&gt;
&lt;br /&gt;
;Battery_ChargeRequest_XX: Dieses Reading signalisiert mit 1 eine Anforderung zur Zwangsladung der Batterie um die Batterie vor Schäden zu schützen (wenn der SOC unter ctrlBatSocManagementXX-&amp;gt;lowSoc gefallen ist) oder wenn der aktuelle SOC unter den berechneten Mindest-SOC gefallen ist.&lt;br /&gt;
&lt;br /&gt;
;Battery_ChargeUnrestricted_XX: Dieses Reading kann den Wert &#039;&#039;&#039;0&#039;&#039;&#039; oder &#039;&#039;&#039;1&#039;&#039;&#039; einnehmen. Ist der Wert 0, sollte die Batterie nur geladen werden, wenn der im Attribut &#039;&#039;plantControl-&amp;gt;feedinPowerLimit&#039;&#039; definierte Wert überschritten wird. Ist der Wert 1, sollte die Batterie mit der vollen zur Verfügung stehenden Ladeleistung angesteuert werden, um wie prognostiziert am Ende des Sonnentages die volle bzw. maximal mögliche Ladung zu erhalten. Der Fokus der Steuerung mit diesem Reading ist es, die Speicherkapazität der Batterie optimal zur Verhinderung der Überschreitung von Einspeiselimits einzusetzen und dennoch einen maximal möglichen SoC am Tagesende zu erreichen. (siehe das beschriebene [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#PV-Prognose_und_Verbrauch_optimierte_Beladungssteuerung_unter_Berücksichtigung_einer_Wirkleistungsbegrenzung|Nutzungsbeispiel]])&lt;br /&gt;
&lt;br /&gt;
;Battery_ChargeOptTargetPower_XX: Dieses Reading enthält einen Richtwert für die optimierte Ladeleistung für jede Batterie. Die Aufladung wird prognosegeführt über den gesamten Tag verteilt, wobei der Fokus auf eine kontinuierliche, aber möglichst niederige Ladeleistung gelegt wird. (siehe diesen [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#leistungsoptimierte_Beladungssteuerung_mit_dem_Fokus_geringe_Verlustleistung_und_Verschleiß|Abschnitt]])  &lt;br /&gt;
&lt;br /&gt;
;Battery_ChargeAbort_XX: Im Attribut &#039;&#039;ctrlBatSocManagementXX&#039;&#039; kann mit dem Schlüssel &#039;&#039;loadAbort&#039;&#039; eine Bedingung definiert werden, bei deren Eintritt die Ladung der Batterie abgebrochen werden soll. In diesem Fall wird &#039;&#039;Battery_ChargeAbort_XX=1&#039;&#039; gesetzt. Mit einem entsprechenden Befehl kann der Anwender das Batteriesystem anweisen den Ladevorgang abzubrechen. &lt;br /&gt;
&lt;br /&gt;
;Battery_TargetAchievable_XX: Diese Reading enthält einen Boolean Wert 0|1 und signalisiert ob der im Attribut &#039;&#039;&#039;ctrlBatSocManagementXX-&amp;gt;loadTarget&#039;&#039;&#039; gesetzte Ziel-SoC lt. Prognose am aktuellen Tag tatsächlich erreicht werden kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Nutzung des Batterie SOC-Management ====&lt;br /&gt;
&lt;br /&gt;
Oftmals wird durch die Anlagenhersteller ein hoher statischer SOC eingestellt bzw. empfohlen, der eine längere Verharrungszeit auf einem tiefen SOC-Wert verhindern soll. Allerdings wechseln sich in auch in den Herbst-, Frühlings- und Wintermonaten Zeiten mit wenig PV-Erzeugung mit Phasen stärkerer Solarstrahlung bei klarem Himmel und Sonnenschein ab.&lt;br /&gt;
&lt;br /&gt;
Ein statischer SOC würde dazu führen, dass in den erwähnten Phasen zuviel Energie in das öffentliche Netz eingespeist wird. Dies soll verhindert werden da die wertvolle Energie besser im eigenen Netz gespeichert und in Dunkelphasen verwendet werden kann. Andererseits soll die Batterie nicht zu lange auf einem tiefen SOC verbleiben und außerdem in gewissen Abständen auf einen so hohen SOC geladen werden der den internen Zellausgleich ermöglicht.&lt;br /&gt;
&lt;br /&gt;
Die SOC Kalkulationsroutine des Moduls errechnet unter Berücksichtigung des prognostizierten PV-Ertrages der kommenden Tage, des aktuellen SOC und der im Attribut &#039;&#039;&#039;ctrlBatSocManagementXX&#039;&#039;&#039; (nachfolgend beschrieben) angegebenen Steuerparameter den Vorschlag für eine optimale SOC-Einstellung. Dabei steht &#039;XX&#039; für die Nummer der Batterie, welche mit dem Attribut setupBatteryDevXX korrespondiert.&lt;br /&gt;
&lt;br /&gt;
Durch das Modul selbst findet keine Steuerung der Batterie statt. Es stellt entsprechende Readings zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::* das Reading &#039;&#039;&#039;Battery_OptimumTargetSoC_XX&#039;&#039;&#039; enthält den vom Modul berechneten optimalen SoC.&lt;br /&gt;
&lt;br /&gt;
::* das Reading &#039;&#039;&#039;Battery_ChargeRequest_XX&#039;&#039;&#039; wird auf &#039;1&#039; gesetzt, wenn der aktuelle SoC unter den optimalen SoC gefallen ist. In diesem Fall sollte die Batterie, unter Umständen mit Netzstrom, zwangsgeladen werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Readings können zur Steuerung des SoC (State of Charge) sowie zur Steuerung des verwendeten Ladestroms der Batterie verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Ermittlung des optimalen SOC erfolgt nach folgender Logik:&lt;br /&gt;
&lt;br /&gt;
# 	Ausgehend von &#039;lowSoc&#039; wird der Mindest-SoC kurz vor Sonnenuntergang um 5% inkrementiert sofern am laufenden Tag &#039;maxSoC&#039; nicht erreicht wurde und die PV-Prognose keinen hinreichenden Ertrag des kommenden Tages vorhersagt. &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# 	Wird &#039;maxSoC&#039; (wieder) erreicht, wird Mindest-SoC um 5%, aber nicht tiefer als &#039;lowSoc&#039;, verringert. Ist der berechnete Mindest-SoC größer als &#039;upSoc&#039;, wird der Mindest-SoC auf &#039;upSoc&#039; gesetzt. &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
#   Mindest-SoC wird soweit verringert, dass die prognostizierte PV Energie des aktuellen bzw. des folgenden Tages von der Batterie aufgenommen werden kann. Mindest-SoC wird typisch auf &#039;upSoc&#039; und nicht tiefer als &#039;lowSoc&#039; verringert.  &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# 	Das Modul erfasst den letzten Zeitpunkt am &#039;maxSoC&#039;-Level, um eine Ladung auf &#039;maxSoC&#039; mindestens alle &#039;careCycle&#039; Tage zu realisieren. Zu diesem Zweck wird der optimierte SoC in Abhängigkeit der Resttage bis zum nächsten &#039;careCycle&#039; Zeitpunkt derart verändert, dass durch eine tägliche 5% SoC-Steigerung &#039;maxSoC&#039; am &#039;careCycle&#039; Zeitpunkt rechnerisch erreicht wird. Wird zwischenzeitlich &#039;maxSoC&#039; erreicht, beginnt der &#039;careCycle&#039; Zeitraum erneut. &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# 	Im fünften Schritt werden die Grenzen &#039;lowSoc&#039; und &#039;upSoc&#039; berücksichtigt. &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# 	Im letzten Schritt erfolgt Generierung des Readings &#039;&#039;&#039;Battery_ChargeRequest_XX&#039;&#039;&#039; zur Signalisierung einer eventuell empfohlenen Zwangsladung auf den berechneten Min-SoC. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bei sehr wenig Erzeugungungsprognose, d.h. wenn sich der berechnete Min-SoC oberhalb von &#039;upSoC&#039; bewegt, wird &#039;upSoC&#039; eingestellt. Liegt der berechnete Min-SoC unterhalb von &#039;upSoC&#039;, ist jedoch größer als &#039;lowSoC&#039;, wird der berechnete SOC im Reading &#039;&#039;&#039;Battery_OptimumTargetSoC_XX&#039;&#039;&#039; eingestellt. Somit eignet sich die Angabe im Schlüssel &#039;upSoC&#039; um in Zeiten geringer Solarenergieerzeugung die Batterie für eine Notstromerzeugung auf mindestens diesem Wert zu halten. Sollte die PV-Prognose kurzfristig einen größeren Ertrag vorhersagen als die Batterie durch die Einhaltung von &#039;upSoC&#039; aufnehmen kann, wird der Min-SoC unter &#039;upSoC&#039; abgesenkt um möglichst allen PV-Überschuß in der Batterie zu speichern und somit dem Eigenverbrauch zuzuführen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der berechnete Mindest-SoC ist immer nur ein unterer Grenzwert. Die Batterie kann durch Ladevorgänge natürlich jederzeit einen höheren als den im Reading &#039;&#039;&#039;Battery_OptimumTargetSoC_XX&#039;&#039;&#039; dargestellten optimalen SoC haben. Der optimale SoC sollte nicht unterschritten werden um die oben genannten Zusammenhänge abbilden zu können.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🎯 &#039;&#039;&#039;Kurzfazit: Was beschreibt Battery_OptimumTargetSoC_XX?&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Battery_OptimumTargetSoC_XX definiert den optimalen Ziel‑SoC, den die Batterie erreichen bzw. nicht unterschreiten sollte, um prognostizierte PV‑Überschüsse aufzunehmen, ausreichende Energiereserven bereitzuhalten und die erforderlichen Pflegezyklen sicherzustellen. Der Wert bezieht sich dabei nicht auf die physikalischen Eigenschaften der Batteriezellen, sondern ergibt sich ausschließlich aus den Steuerungszielen des Moduls – basierend auf den eingestellten Parametern und den prognostizierten Umweltfaktoren. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
===== Die dynamische SOC Steuerung mit Umsetzungsbeispiel =====&lt;br /&gt;
Das Modul bietet eine Unterstützung zur automatisierten Einstellung eines optimalen SoC Wertes.&lt;br /&gt;
&lt;br /&gt;
Ziel ist es, den Minimum SoC in Abhängigkeit der zu erwartenden Solarerträge des aktuellen und des folgenden Tages so einzustellen, dass der prognostizierte Solarertrag von der Batterie aufgenommen werden kann. Die Einspeisung in das öffentliche Netz soll minimiert werden.&lt;br /&gt;
&lt;br /&gt;
Weiterhin soll ein unterer SoC nicht unterschritten, sowie ein oberer Minimum SoC im Normalfall nicht überschritten werden. Der obere Grenzwert stellt sicher, dass die Batterie mindestens bis zu diesem Wert wieder entladen werden kann. Dadurch bleibt innerhalb der Batterie immer genügend Kapazität verfügbar um unvorhergesehene PV Energie aufnehmen zu können.&lt;br /&gt;
&lt;br /&gt;
Aktiviert wird die Unterstützung der Batteriesteuerung durch das Setzen des Attributes &#039;&#039;&#039;ctrlBatSocManagementXX&#039;&#039;&#039; z.B. mit diesen Angaben:&lt;br /&gt;
&lt;br /&gt;
 ctrlBatSocManagementXX lowSoc=x upSoC=x maxSoC=x careCycle=x &lt;br /&gt;
&lt;br /&gt;
so zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 ctrlBatSocManagement01 lowSoc=10 upSoC=50 maxSoC=98 careCycle=20&lt;br /&gt;
&lt;br /&gt;
Dabei steht &#039;XX&#039; für die Nummer der Batterie, welche mit dem Attribut setupBatteryDevXX korrespondiert. &lt;br /&gt;
Ist dieses Attribut gesetzt, werden Steuerungs-Readings erstellt, die der Nutzer auswerten und seine Batterieanlage z.B. via notify oder DOIF steuern kann. &amp;lt;bR&amp;gt;&lt;br /&gt;
Das Reading &#039;&#039;&#039;Battery_OptimumTargetSoC_XX&#039;&#039;&#039; enthält den vom Modul berechneten optimalen Mindest-SoC.&lt;br /&gt;
Das Reading &#039;&#039;&#039;Battery_ChargeRequest_XX&#039;&#039;&#039; wird auf &#039;1&#039; gesetzt, wenn der aktuelle SOC unter den optimalen SOC bzw. minimalen SOC gefallen ist.&lt;br /&gt;
&lt;br /&gt;
Die Schlüssel &#039;&#039;&#039;lowSoc&#039;&#039;&#039; und &#039;&#039;&#039;upSoC&#039;&#039;&#039; sind die unteren und oberen Grenzen, zwischen denen sich der Minimum SoC im normalen Betrieb bewegen soll.&lt;br /&gt;
Der Schlüssel &#039;&#039;&#039;maxSoC&#039;&#039;&#039; stellt eine Ladungsgrenze dar, die mindestens alle X (careCycle) Tage erreicht werden soll. Zu diesem Zweck errechnet das Modul die Anzahl der nötigen Erhöhungen der Minimum Batterieladung von 5% pro Tag um ausgehend vom aktuellen SoC-Level. Der resultierende Minimum SoC Wert wird entsprechend angepasst. Wurde der einstellte maxSoC Level erreicht, startet der Wartungszyklus (careCycle) erneut. &amp;lt;br&amp;gt;&lt;br /&gt;
Der maxSoC in Verbindung mit dem durch &#039;&#039;&#039;careCycle&#039;&#039;&#039; definierten Zyklus soll sicherstellen, dass der Batterieverbund in regelmäßigen Abständen einen Ladungsausgleich vollziehen kann. &lt;br /&gt;
&lt;br /&gt;
Durch die Modullogik erfolgt eine 5 protentige Anhebung des Minimum SoC wenn am Vortag maxSoC nicht erreicht wurde. Die Anhebung erfolgt aber nicht über upSoC. upSoC ist die obere Grenze des Minimum SoC. Wird am Vortag mindestens die maxSoC Ladung erreicht, verringert sich der Minimum SoC wieder schrittweise um 5%, aber nicht tiefer als lowSoc.&lt;br /&gt;
&lt;br /&gt;
Ergänzt wird die Logik noch um die PV Vorhersage. Dabei wird die obige Minimum SoC Berechnung um die erwartete PV Erzeugung des aktuellen und folgenden Tages korrigiert. Das bedeutet, dass der Minimum SoC z.B. von heute 50% auf 10% abgesenkt und dadurch die gespeicherte Energie dem Haushalt zugeführt wird, wenn am heutigen oder kommenden Tag eine entsprechende PV Energie zu erwarten ist um die Batterie wieder vollständig zu laden.&lt;br /&gt;
Dadurch ist immer genügend &amp;quot;Freiplatz&amp;quot; in der Batterie und andererseits hat die Batterie in langen Dunkelphasen eine Reserve für einen eventuellen Stromausfall (falls der abgesichert werden soll) und wird vor einem dauerhaften tiefen SoC geschützt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
===== Umsetzungsbeispiel =====&lt;br /&gt;
&lt;br /&gt;
Wie das Reading &#039;&#039;&#039;Battery_OptimumTargetSoC_XX&#039;&#039;&#039; genutzt werden kann, wird am Beispiel einer Victron Batterieanlage gezeigt. Die Anlage wird durch Cerbo GX Gerät gesteuert. Der Cerbo GX ist per MQTT2 in FHEM eingebunden. Umgesetzt ist die Steuerung der Batterie &#039;01&#039;, d.h. die Angabe &#039;XX&#039; ist durch &#039;01&#039; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die folgende kleine Logik ist in einem &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039; File eingebaut und wird regelmäßig mit&lt;br /&gt;
&lt;br /&gt;
 batSocChargeMgmnt (&#039;&amp;lt;Name SolarForecast Device&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
aufgerufen. Der Aufruf erfolgt durch Angabe der Routine im Attribut &#039;&#039;&#039;ctrlUserExitFn&#039;&#039;&#039; des SolarForecast Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{  &lt;br /&gt;
  # Hinweis: die Zeichen &#039;::&#039; vor der Routine sind durch das SolarForecast Package bedingt&lt;br /&gt;
  ::batSocChargeMgmnt ($name);&lt;br /&gt;
  return;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Routine wird dadurch automatisch am Ende jedes Zyklus (siehe Attribut plantControl-&amp;gt;cycleInterval) ausgeführt.&lt;br /&gt;
Um die SOC Managementfunktion nach Bedarf ein- bzw. ausschalten zu können wird zunächst im SolarForecast Device ein userattr zur Steuerung der SOC-Logik angelegt:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Device&amp;gt; userattr userFn_BatterySoCManagement:ein,aus&lt;br /&gt;
&lt;br /&gt;
Die Perl Routine &#039;&#039;&#039;batSocChargeMgmnt&#039;&#039;&#039; ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
###############################################################################&lt;br /&gt;
#&lt;br /&gt;
# Save this file as 99_mySolarForecastUtils.pm, and create your own functions&lt;br /&gt;
# in the new file. They are then available in every Perl expression.&lt;br /&gt;
#&lt;br /&gt;
###############################################################################&lt;br /&gt;
 package main;&lt;br /&gt;
 use strict;&lt;br /&gt;
 use warnings;&lt;br /&gt;
&lt;br /&gt;
 sub&lt;br /&gt;
 mySolarForecastUtils_Initialize($$)&lt;br /&gt;
 {&lt;br /&gt;
   my ($hash) = @_;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
# ab hier eigenen Code eintragen&lt;br /&gt;
###############################################################################&lt;br /&gt;
&lt;br /&gt;
############################################################################&lt;br /&gt;
#      Batterie SOC und Max. Ladestrom Management&lt;br /&gt;
############################################################################&lt;br /&gt;
sub batSocChargeMgmnt {&lt;br /&gt;
  my $name = shift;&lt;br /&gt;
  my $bn   = &#039;01&#039;;                                                                      # Batterienummer (evtl. im Aufruf mitgeben)&lt;br /&gt;
  my $hash = $defs{$name};&lt;br /&gt;
  &lt;br /&gt;
  my $vebus   = &#039;MQTT2_cerboGX_c0619ab34e08_vebus&#039;;                                     # Victron Vebus Device&lt;br /&gt;
  my $vicsets = &#039;MQTT2_cerboGX_c0619ab34e08_settings&#039;;                                  # Victron Einstellungen&lt;br /&gt;
&lt;br /&gt;
  my $maxcspc = 105;                                                                    # max. Ladestrom (A) für Victron MPII Verbund&lt;br /&gt;
  my $preduce = FHEM::SolarForecast::BatteryVal ($name, $bn, &#039;bpinreduced&#039;, $maxcspc);  # reduzierte Ladeleistung aus Bat-Konfig (W)&lt;br /&gt;
  my $actmcc  = ReadingsNum ($vicsets, &#039;MaxChargeCurrent&#039;, undef);                      # akt. Ladestromeinstellung&lt;br /&gt;
  my $load    = $actmcc // $maxcspc;                                                    # Soll-Ladestrom (A)  &lt;br /&gt;
&lt;br /&gt;
  ## Battery SoC Management&lt;br /&gt;
  ###########################&lt;br /&gt;
  my $ubsm = AttrVal ($name, &#039;userFn_BatterySoCManagement&#039;, &#039;aus&#039;); &lt;br /&gt;
  &lt;br /&gt;
  if ($ubsm eq &#039;ein&#039;) { &lt;br /&gt;
    my $bcrq = ReadingsNum ($name,    &#039;Battery_ChargeRequest_&#039;.$bn,     0);&lt;br /&gt;
    my $csoc = ReadingsNum ($vicsets, &#039;MinimumSocLimit&#039;,               10);             # akt. SoC&lt;br /&gt;
    my $osoc = ReadingsNum ($name,    &#039;Battery_OptimumTargetSoC_&#039;.$bn, 10);             # Soll-SoC&lt;br /&gt;
	my $surp = ReadingsNum ($name,    &#039;Current_Surplus&#039;,                0);             # aktueller PV-Überschuß&lt;br /&gt;
	&lt;br /&gt;
    if ($csoc != $osoc) {&lt;br /&gt;
      CommandSet (undef, &amp;quot;$vicsets MinimumSocLimit $osoc&amp;quot;);&lt;br /&gt;
      Log3 ($name, 3, qq{$name - userFn SoCMgmnt -&amp;gt; MinimumSocLimit in $vicsets set to $osoc %});&lt;br /&gt;
    }&lt;br /&gt;
	                                           &lt;br /&gt;
    if ($bcrq &amp;amp;&amp;amp; $surp &amp;lt; 1000) {                                                       # max. Ladestrom (A) b. Battery_ChargeRequest&lt;br /&gt;
      $load = $preduce / 48;                                                           # bei 48V Batteriesystem&lt;br /&gt;
    }&lt;br /&gt;
	else {&lt;br /&gt;
	  $load = $maxcspc;&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  ## Einstellung MPII Verbund MaxChargeCurrent&lt;br /&gt;
  ##############################################&lt;br /&gt;
  if ($actmcc &amp;amp;&amp;amp; $load != $actmcc) {&lt;br /&gt;
    CommandSet (undef, &amp;quot;$vicsets MaxChargeCurrent $load&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
    Log3 ($name, 3, qq{$name - userFn ChargeMgmnt -&amp;gt; MaxChargeCurrent in $vicsets set }.&lt;br /&gt;
                    qq{from old $actmcc A to $load A});&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  readingsSingleUpdate ($hash, &#039;userFn_MPII_MaxChargeCurrent_set&#039;, $load, 0);&lt;br /&gt;
  &lt;br /&gt;
return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
###############################################################################&lt;br /&gt;
# Ende eigener Code&lt;br /&gt;
&lt;br /&gt;
1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ist im SolarForecast Device das Reading  &#039;&#039;&#039;Battery_ChargeRequest_01&#039;&#039;&#039; gesetzt, ist der aktuelle SOC kleiner als der optimale SOC und die Batterie wird (eventuell aus dem öffentlichen Netz) geladen. Das kann automatisch durch den Cerbo GX bzw. in anderen Anlagen durch einen entsprechenden Befehl erfolgen.&lt;br /&gt;
Damit die Netzbeladung nicht mit der vollen Ladestromstärke geschieht, wird der Ladestrom auf den gewünschten Wert (hier 21 A -&amp;gt; ca. 1000 W bei einem 48V System) reduziert sofern kein oder zu wenig PV-Überschuß vorhanden ist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== weitere mögliche Aspekte der SOC- und Batterieladesteuerung ====&lt;br /&gt;
&lt;br /&gt;
SolarForecast liefert durch seine internen Logiken bereits sehr hilfreiche Signale zur Steuerung von Batteriesystemen in Form von Readings an. Abhängig von den individuellen Möglichkeiten der vorhandenen Anlage käme zum Beispiel zusätzlich zu einer Steurung des optimalen SOC oder der Zeitfenster für die Batterieaufladung auch eine Steuerung des Ladestroms bzw. der verwendeten Ladeleistung in Betracht.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hintergründe:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Das Laden eines Akkus mit möglichst gleichbleibender und geringer Leistung wirkt sich positiv auf dessen Langlebigkeit aus, was u.a. auch daran liegt, dass der Temperaturstreß im Akku bei langsamer Energiezuführung nur gering ist.&lt;br /&gt;
&lt;br /&gt;
* Ein geringer Ladestrom führt zu einem geringen Absacken der Akkuspannung beim (ggf, temporären) Abschalten des Ladestroms, was sich positiv auf die SOC-Schätzung auswirkt.&lt;br /&gt;
    &lt;br /&gt;
* Ein geringer Ladestrom führt, insb. bei Nutzung passiver Balancer (sind in den Akku-Systemen üblicherweise verbaut), zu einer geringen Differenz zwischen den einzelnen Zellspannungen und damit zu einer besseren Kapazitätsausnutzung eins Akkus.&lt;br /&gt;
&lt;br /&gt;
* Ein geringer Ladestrom kann zu einem zeitlich punktgenauen Zielfüllstand (im Winter 100%, ansonsten natürlich weniger) am Ende des Tages führen.&lt;br /&gt;
    &lt;br /&gt;
* Eine geringer Ladestrom führt auch zu geringen Leitungsverlusten, da der Strom quadratisch zu den Leitungsverlusten beiträgt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Weiterhin kann auch die Verweildauer oder die Begrenzung des SOC, auf den die Batterie maximal geladen werden soll, Gegenstand von Optimierungen sein.&lt;br /&gt;
&lt;br /&gt;
Die häufig zu findende Empfehlung, Akkus nicht zu lange bei einem SOC von 100% verweilen zu lassen, liegt weniger an dem SOC als solchem, sondern daran, dass &#039;&#039;SOC=100%&#039;&#039; üblicherweise dadurch ermittelt wird, dass eine Zelle im Akku einen Spannungsschwellenwert überschreitet, der – würde dieser Schwellenwert zeitlich länger überschritten sein – zu einer Schädigung des Akkus führen könnte. Schädlich sind insbesondere häufige Nachladevorgänge bei Werten um die 100% SOC, da Zellen dann ja häufiger und damit - integral gesehen - auch länger den o.g. Schwellenwert überschreiten.&lt;br /&gt;
&lt;br /&gt;
Einige Akku-Hersteller, z.B. BYD, haben auf o.g, Grund in der (neueren) Firmware Ihrer Systeme einen SOC-Threshold (bei BYD liegt dieser bei 95%) eingebaut. Dieser Wert muss nach einem erreichten SOC von 100% unterschritten  werden, bevor überhaupt eine weitere Ladung erfolgt. Insbesondere in der dunklen Jahreszeit kann es daher sinnvoll sein, den Akku unter Verwendung von PV-Leistung so zu füllen, dass dieser möglichst nur einmal vor Einbruch der Dunkelheit auf &#039;&#039;SOC=100%&#039;&#039; geladen wird. Hierbei sollte darauf geachtet werden, dass der Ladeschlussstrom des jeweiligen Systems nicht unterschritten wird. &lt;br /&gt;
&lt;br /&gt;
SolarForecast unterstützt die oben betrachtete Batteriesteuerung durch die optionale Angabe von &#039;&#039;&#039;loadAbort&#039;&#039;&#039; im Attribut &#039;&#039;&#039;ctrlBatSocManagementXX&#039;&#039;&#039;. Das in diesem Kontext erstellte Reading &#039;&#039;&#039;Battery_ChargeAbort_XX&#039;&#039;&#039; stellt die auswertbaren Steuerungsinformationen zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== PV-Prognose und Verbrauch optimierte Beladungssteuerung unter Berücksichtigung einer Wirkleistungsbegrenzung ====&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2025-04-25 143910.png|right|thumb|400px|Batterie Popup &amp;quot;nur laden wenn Einspeiselimit überschritten&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
Die in diesem Abschnitt beschriebene Ladestrategie &#039;&#039;&#039;loadRelease&#039;&#039;&#039; wird im Modul als &#039;&#039;&#039;Ladefreigabe&#039;&#039;&#039; bezeichnet.&lt;br /&gt;
&lt;br /&gt;
Üblicherweise wird die Batterie geladen. sobald PV-Überschuß vorhanden ist ohne eine Prognose zu berücksichtigen. Dadurch sind die Batterien im Sommer unter Umständen schon um 10-12 Uhr voll geladen und die Anlage liefert ihre mehr oder weniger volle Energie (je nach Ausrichtung) in das öffentliche Netz. Dann könnte es zu einer Begrenzung der PV-Leistung durch einen Schwellenwert (z.B. 70%-Regelung) oder eventuell Zwangsabregelung durch den Netzbetreiber kommen.&lt;br /&gt;
&lt;br /&gt;
Hintergrund dieser Erweiterung ist das Bestreben, eine optimale Unterstützung bei der Maximierung des Eigenverbrauchs zu geben und einen Beitrag zur Netzstabilität zu leisten.&lt;br /&gt;
Das Ziel der Beladungssteuerung der Batterie ist es, die Ladung der Batterie über den Tag verteilt so zu steuern, dass die Batterie erst dann geladen wird, wenn durch den PV-Überschuß eine Netzeinspeisung erfolgen würde bzw. ein Grenzwert erreicht werden würde, der zu einer Abregelung der PV-Anlage führen könnte.&lt;br /&gt;
Es kann auch zu einer Zwangsabregelung durch den Netzbetreiber führen, was vermieden werden soll.&lt;br /&gt;
 &lt;br /&gt;
Die interne Kalkulationslogik erstellt zu diesem Zweck ein Reading &#039;&#039;&#039;Battery_ChargeUnrestricted_XX&#039;&#039;&#039;.&lt;br /&gt;
Dieses Reading gibt dem User ein Signal, ob zu der aktuellen Stunde der Ladevorgang der Batterie freigegeben (1) oder nicht freigegeben werden sollte (0). Die Freigabe zur Ladung bedeutet dass:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Battery_ChargeUnrestricted_XX=1&#039;&#039;&#039; die Batterie mit ihrer vollen, oder der im Reading [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#leistungsoptimierte_Beladungssteuerung_mit_dem_Fokus_geringe_Verlustleistung_und_Verschleiß|Battery_ChargeOptTargetPower_XX]] angegebenen Ladeleistung angesteuert werden sollte um wie prognostiziert am Ende des Sonnentages die volle bzw. maximal mögliche Ladung zu erhalten..&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Battery_ChargeUnrestricted_XX=0&#039;&#039;&#039; die Batterie nur geladen werden sollte wenn der im Attribut plantControl-&amp;gt;feedinPowerLimit definierte Wert überschritten wird&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
Ist keine Freigabe zur Ladung vorhanden, kann bzw. sollte dennoch eine Ladung der Batterie vorgenommen werden, sofern eine über dem im &amp;lt;br&amp;gt;&lt;br /&gt;
Attribut &#039;&#039;&#039;plantControl-&amp;gt;feedinPowerLimit&#039;&#039;&#039; definierten Limit liegende Einspeiseleistung vorhanden ist. In diesem Status sollte die Batterie nur mit der Differenzleistung von vorhandener Einspeiseleistung und dem gesetzen Einspeiselimit geladen werden und damit das gesetzte Einspeiselimit einhalten ohne die Anlage abzuregeln. Ist die Batterie in einer Balkengrafikebene dargestellt, wird im Mouse-Over Popup die Battrie mit &#039;&#039;&amp;quot;nur laden wenn Einspeiselimit überschritten&amp;quot;&#039;&#039; gekennzeichnet.&lt;br /&gt;
&lt;br /&gt;
Die Möglichkeiten der Batteriesteuerung sind stark von der individuellen Anlage abhängig und können hier nicht beschrieben werden. Ein Umsetzungsbeispiel mit einer Victron-Anlage mit Pylontech Batterie ist weiter unten dargestellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
===== Aktivierung und Arbeitsweise =====&lt;br /&gt;
&lt;br /&gt;
Die implementierte Logik zur optimierten Batterie Beladungssteuerung wird aktiviert, wenn folgende Kriterien erfüllt sind: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* der Schlüssel &#039;&#039;&#039;capacity&#039;&#039;&#039; in den setupInverterDevXX Atributen ist gesetzt&lt;br /&gt;
* das Attribut &#039;&#039;&#039;ctrlBatSocManagementXX&#039;&#039;&#039; für die jeweilige Batterie ist gesetzt&lt;br /&gt;
* der Schlüssel &#039;&#039;&#039;cap&#039;&#039;&#039; im Attribut setupBatteryDevXX der jeweiligen Batterie ist gesetzt&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Die Logik arbeitet wie folgt:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der resultierende Schwellenwert der Wirkleistungsbegrenzung: der Gesamtanlage wird durch die Auswertung der in den Inverter-Attributen setupInverterDevXX  gesetzen Schlüssel limit (optional) und capacity ermittelt. Inverter mit gesetztem Schlüssel feed = grid (deren Energie wird ausschließlich in das öffentlich Netz eingespeist) werden von der Betrachtung in diesem Kontext ausgeschlossen.&lt;br /&gt;
&lt;br /&gt;
;Die benötigte Beladung bis zu maxSoC (im Attribut setupBatteryDevXX) : wird ermittelt und mit der zu erwartenden PV Tagesprognose in Beziehung gesetzt. Sofern die PV-Erzeugung abzgl. Verbrauch noch nicht das Wirkleistungbegrenzungs-Limit erreicht UND noch genügend PV-Überschuß für eine Ladung auf &#039;&#039;maxSoC&#039;&#039; im Laufe der kommenden Stunden des Tages zu erwarten ist, bleibt das Reading &#039;&#039;&#039;Battery_ChargeUnrestricted_XX = 0&#039;&#039;&#039;. Die erreichte Qualität der Steuerungslogik ist stark von der Prognosequaliät abhängig. Um die Steuerung resilienter zu gestalten, wird per default ein Sicherheitsaufschlag von 50% auf die prognostizierte benötigte Ladeenenergie auf Stundenbasis einkalkuliert. Dieser Wert kann mit dem Attribut &#039;&#039;&#039;ctrlBatSocManagementXX-&amp;gt;safetyMargin&#039;&#039;&#039; individuell angepasst werden.&lt;br /&gt;
&lt;br /&gt;
;Wird das Wirkleistungbegrenzungs-Limit erreicht/überschritten und/oder die PV-Überschußprognose: zzgl. eines Sicherheitspuffers unterschritten, wird &#039;&#039;&#039;Battery_ChargeUnrestricted_XX = 1&#039;&#039;&#039; gesetzt. Der User kann darauf reagieren und den Batterie Ladevorgang aktivieren. Die Möglichkeiten der Aktivierung sind natürlich von der installierten Anlage abhängig. Das SolarForecast Device greift nicht in die Batteriesteuerung direkt ein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Anders ausgedrückt erfolgt immer dann eine Ladefreigabe, wenn einer der nachfolgenden Sachverhalte &#039;&#039;wahr&#039;&#039; ist:&lt;br /&gt;
&lt;br /&gt;
- die benötigte Ladeenergie (aller installierten Batterien) &amp;gt;= PV-Restüberschuß des Tages (Reading RestOfDayPVforecast) zzgl. Sicherheitsaufschlag&lt;br /&gt;
&lt;br /&gt;
ODER&lt;br /&gt;
&lt;br /&gt;
- der Zeitpunkt des PV-Erzeugungszenit des laufenden Tages überschritten ist (Reading Today_MaxPVforecastTime)&lt;br /&gt;
&lt;br /&gt;
ODER&lt;br /&gt;
&lt;br /&gt;
- wenn die aktuelle PV Leistung &amp;gt;= einer eventuellen Wechselrichter-Leistungsbegrenzung ist (Summe aller WR-Begrenzungen)&lt;br /&gt;
&lt;br /&gt;
ODER&lt;br /&gt;
&lt;br /&gt;
- wenn das BatSoc-Management _nicht_ aktiviert ist (nicht alle oben genannten Aktivierungskriterien erfüllt sind)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sind mehrere Batterien installiert und durch das Management einer Batterie die Einhaltung der genannten Kriterien bzw. Sachverhalte erwirkt wird, bleiben die weiteren Batterien im Modus Ladefreigabe (Battery_ChargeUnrestricted_XX=1).  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Umsetzungsbeispiel Batterie Ladesteuerung mit Victron GX Venus über den Grid Setpoint =====&lt;br /&gt;
&lt;br /&gt;
Ziel der Steuerung ist es abhängig vom Wert des Readings Battery_ChargeUnrestricted_XX (z.B. Battery_ChargeUnrestricted_01) die Ladung des angeschlossenen Batteriesystems zu aktivieren bzw. zu deaktivieren.&lt;br /&gt;
Das vorliegende Beispiel soll umzusetzen:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Battery_ChargeUnrestricted_01 = 0 -&amp;gt; Batterie nicht aufladen bzw. nur laden wenn Einspeiselimit überschritten (Attribut plantControl-&amp;gt;feedinPowerLimit)&lt;br /&gt;
* Battery_ChargeUnrestricted_01 = 1 -&amp;gt; Batterie aufladen&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der Grid Setpoint ist ein Parameter in den Victron Systemeinstellungen. Das Victron System wird den eingestellten Grid Setpoint versuchen einzuhalten und bei einem positiven Wert Energie aus dem Netz beziehen bzw. bei einem negativen Grid Setpoint Energie in das Netz einspeisen.&lt;br /&gt;
&lt;br /&gt;
Normalerweise wird das Victron System die erzeugte PV Energie zunächst zur Deckung des Hausverbrauchs verwenden, ist dann noch ein PV Überschuß vorhanden, die Batterien aufladen und bei weiter vohandenen PV Überschuß diese Energie in das öffentliche Netz einspeisen sofern dem System eine Einspeisung erlaubt ist. Anderenfalls werden die Wechselrichter oder MPPT Smartloader heruntergeregelt bzw. limitiert. &lt;br /&gt;
&lt;br /&gt;
In der Standardeinstellung ist beim Victron System ein Grid Setpoint von ca. 20 bis 50 Watt, d.h. das System strebt danach diese Vorgabe zu erfüllen zieht ständig Energie in diesem Bereich aus dem öffentlich Netz von einem gelegentlichen Überschwingen der Regelung abgesehen. Damit ein eventueller PV Überschuß nicht zum Laden der Batterie verwendet, sondern statt dessen in das öffentliche Netz eingespeist wird, muß der Grid Setpoint um diesen Betrag abgesenkt werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2025-02-24 114403.png|right|thumb|400px|Integration des Grid Setpoint-Managements in den Own_Spec-Bereich]]&lt;br /&gt;
&lt;br /&gt;
Damit man später per Attribut bzw. über den [[#Formatierung_der_Inhalte_im_Bereich_&amp;quot;Graphic_Header_Own_Specification&amp;quot;|Own_Spec-Bereich]] die automatische Ladesteuerung über den Grid Setpoint ein- bzw. ausschalten kann, legen wir ein userattr an:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 userattr &amp;lt;Name&amp;gt; userFn_GridSetpointManagement:ein,aus&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Weiterhin sind einige Vorbereitungen im Device MQTT2_cerboGX_c0619ab34e08_settings vorzunehmen. Dieses Device ist im vorliegenden Beispiel ein in FHEM vorhandenes MQTT2_DEVICE, über das die Victron CerboGX Einstellungen zugreifbar sowie einstellbar sind. Die Vorgehensweise zur Erstellung des MQTT2_DEVICE ist hier nicht beschrieben und wird vorausgesetzt.&lt;br /&gt;
&lt;br /&gt;
Damit ein entsprechender Set-Befehl zur Einstellung des Grid Setpoints vorhanden ist, werden folgende Attribute gesetzt:&lt;br /&gt;
&lt;br /&gt;
 attr MQTT2_cerboGX_c0619ab34e08_settings jsonMap Settings_CGwacs_AcPowerSetPoint_value:GridSetpoint&lt;br /&gt;
 attr MQTT2_cerboGX_c0619ab34e08_settings setList GridSetpoint W/c0619ab34e08/settings/0/Settings/CGwacs/AcPowerSetPoint {&amp;quot;value&amp;quot;:$EVTPART1}&lt;br /&gt;
&lt;br /&gt;
Nach dieser Attributierung kann mit einem &amp;quot;&#039;&#039;set MQTT2_cerboGX_c0619ab34e08_settings GridSetpoint &amp;lt;Wert&amp;gt;&#039;&#039;&amp;quot; der Grid Setpoint eingestellt werden.&lt;br /&gt;
&lt;br /&gt;
Das Attribut userFn_GridSetpointManagement kann nun im Perl Code ausgewertet werden um das Grid Setpoint-Management ein- bzw. auszuschalten.&lt;br /&gt;
Der nachfolgende Code wird in die Datei &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039; eingefügt. Ist diese Datei nicht vorhanden, legen wir sie vorab als Kopie der ausgelieferten 99_myUtils.pm an.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible mw-collapsed&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Code Management Batterieladung über Victron Grid Setpoint -&amp;gt;&#039;&#039;&#039; &amp;lt;div class=&amp;quot;mw-collapsible-content&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
###############################################################################&lt;br /&gt;
#&lt;br /&gt;
# Save this file as 99_mySolarForecastUtils.pm, and create your own functions&lt;br /&gt;
# in the new file. They are then available in every Perl expression.&lt;br /&gt;
#&lt;br /&gt;
###############################################################################&lt;br /&gt;
 package main;&lt;br /&gt;
 use strict;&lt;br /&gt;
 use warnings;&lt;br /&gt;
&lt;br /&gt;
 sub&lt;br /&gt;
 mySolarForecastUtils_Initialize($$)&lt;br /&gt;
 {&lt;br /&gt;
   my ($hash) = @_;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
# ab hier eigenen Code eintragen&lt;br /&gt;
###############################################################################&lt;br /&gt;
&lt;br /&gt;
############################################################################&lt;br /&gt;
#   Steuerung Start/Stop der Batterieladung über den Victron Grid Setpoint&lt;br /&gt;
############################################################################&lt;br /&gt;
sub gridSetpointMgmt {&lt;br /&gt;
  my $name = shift;&lt;br /&gt;
  my $hash = $defs{$name};&lt;br /&gt;
  &lt;br /&gt;
  my $vicsets   = &#039;MQTT2_cerboGX_c0619ab34e08_settings&#039;;                               # Device Victron Einstellungen&lt;br /&gt;
  my $gspdef    = 20;                                                                  # Default Einstellung des Grid Setpoint&lt;br /&gt;
  my $targetgsp = $gspdef;                                                             # Voreinstellung Grid Setpoint&lt;br /&gt;
  my $neggspmax = FHEM::SolarForecast::CurrentVal ($name, &#039;feedinPowerLimit&#039;, 5000);   # max. gewünschte Einspeiseleistung in Watt&lt;br /&gt;
  $neggspmax    = $neggspmax * -1;&lt;br /&gt;
  my $gspm      = AttrVal ($name, &#039;userFn_GridSetpointManagement&#039;, &#039;aus&#039;);             # Freischaltung des Grid Setpoint-Managements&lt;br /&gt;
  my $curgsp    = ReadingsNum ($vicsets, &#039;GridSetpoint&#039;,         $gspdef);             # aktuelle Einstellung Grid Setpoint&lt;br /&gt;
  &lt;br /&gt;
  if ($gspm eq &#039;ein&#039;) { &lt;br /&gt;
    my $bcrq = ReadingsNum ($name, &#039;Battery_ChargeUnrestricted_01&#039;, 0);         # Ladefreigabe (1 -&amp;gt; Bat Ladefreigabe)&lt;br /&gt;
    my $surp = ReadingsNum ($name, &#039;Current_Surplus&#039;,               0);         # aktueller PV-Überschuß&lt;br /&gt;
	&lt;br /&gt;
    if (!$bcrq) {                                                               # Grid Setpoint absenken wenn keine .. &lt;br /&gt;
        $targetgsp = $gspdef - $surp;                                           # ..Batterie Ladefreigabe&lt;br /&gt;
        $targetgsp = $neggspmax if($targetgsp &amp;lt; $neggspmax);                    # Begrenzung der Einspeiseleistung&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  if ($curgsp != $targetgsp) {&lt;br /&gt;
	  fhem (&amp;quot;set $vicsets GridSetpoint $targetgsp&amp;quot;);&lt;br /&gt;
      Log3 ($name, 3, qq{$name - userFn gridSetpointMgmt -&amp;gt; GridSetpoint in $vicsets set to $targetgsp});&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  readingsSingleUpdate ($hash, &#039;userFn_Victron_GridSetpoint_set&#039;, $targetgsp, 0);&lt;br /&gt;
  &lt;br /&gt;
return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
###############################################################################&lt;br /&gt;
# Ende eigener Code&lt;br /&gt;
&lt;br /&gt;
1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der Vergleich des Setpoints mit der Vorgabe von &#039;&#039;$neggspmax&#039;&#039; dient dazu die maximale Einspeiseleistung in das öffentliche Netz zu begrenzen. Ist diese Grenze erreicht, wird der noch verbleibende Überschuß in die Batterie geladen. Dadurch wird eine Abregelung der Anlage vermieden wenn der Schwellenwert &#039;&#039;$neggspmax&#039;&#039;erreicht ist sofern die Batterie aufnahmefähig ist und nicht voll geladen ist. &lt;br /&gt;
&lt;br /&gt;
Damit die Routine mit jedem Zyklus im Modul ausgeführt wird, legen wir sie im Attribut &#039;&#039;&#039;ctrlUserExitFn&#039;&#039;&#039; an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr &amp;lt;Name&amp;gt; ctrlUserExitFn  {  &lt;br /&gt;
                               ::gridSetpointMgmt  ($name);&lt;br /&gt;
                            }&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zum Management des automatischen Grid Setpoint und der Anzeige des eingestellten Wertes wird das Attribut und die Readinganzeige in den Own_Spec-Bereich eingebunden, z.B.:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; graphicHeaderOwnspec  #Settings&lt;br /&gt;
                                   SetPoint&amp;amp;nbsp;Management:userFn_GridSetpointManagement&lt;br /&gt;
                                   Grid&amp;amp;nbsp;Setpoint:GridSetpoint@MQTT2_cerboGX_c0619ab34e08_settings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== leistungsoptimierte Beladungssteuerung mit dem Fokus geringe Verlustleistung und Verschleiß ====&lt;br /&gt;
&lt;br /&gt;
Über das Attribut ctrlBatSocManagementXX kann mit dem Schlüssel loadStrategy die Ladestrategie &#039;&#039;&#039;optPower&#039;&#039;&#039; oder &#039;&#039;&#039;smartPower&#039;&#039;&#039; eingestellt werden.&lt;br /&gt;
Das SF-Modul bietet ein weiteres Reading &#039;&#039;&#039;Battery_ChargeOptTargetPower_XX&#039;&#039;&#039; zur Batteriesteuerung an. Dieses Reading liefert eine kalkulierte optimale Ladeleistung in Watt.&lt;br /&gt;
&lt;br /&gt;
Die in diesem Abschnitt beschriebene Ladestrategie &#039;&#039;&#039;optPower&#039;&#039;&#039; wird im Modul als &#039;&#039;&#039;optimierte Ladeleistung&#039;&#039;&#039;, die Ladestrategie &#039;&#039;&#039;smartPower&#039;&#039;&#039; als &#039;&#039;&#039;zieloptimierte Ladeleistung&#039;&#039;&#039; bezeichnet.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Beide Strategien kalkulieren die Ladeleistung kontinuierlich neu und berücksichtigen dabei:&lt;br /&gt;
&lt;br /&gt;
* die Prognose der PV-Erzeugung der nächsten Stunden und des (Rest-)Tages&lt;br /&gt;
* den prognostizierten Verbrauch auf Stunden- bzw. Tagesbasis&lt;br /&gt;
* eine eventuell mögliche Überschreitung des gesetzten Einspeiselimits (plantControl-&amp;gt;feedinPowerLimit)&lt;br /&gt;
* die gesetzten Leistungsparameter der Batterie &lt;br /&gt;
* das Ziel, am Tagesende einen möglichst maximalen SoC der Batterie erreicht zu haben bzw. den eingestellten Ziel-SoC &#039;&#039;&#039;loadTarget&#039;&#039;&#039;&lt;br /&gt;
* die Effizienz der Batterieanlage (Einstellung &#039;&#039;&#039;setupBatteryDevXX-&amp;gt;efficiency&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der Fokus der implementierten Logik liegt dabei auf einer kontinuierlichen Ladeleistung, die aber unter den oben genannten Gesichtspunkten möglichst (relativ) gering sein soll um den Batterieverschleiß und die Verlustleistung zu minimieren. Die im Reading angezeigte Ladeleistung kann mit geeigneten Mitteln direkt in die Leistungssteuerung der Batterie eingebracht werden. Natürlich kann die Leistung auch vorab in einen optimalen Ladestrom umgerechnet werden.&lt;br /&gt;
&lt;br /&gt;
Da das Ergebnis der Kalkulation stark von den Prognosen abhängt, ist zur Erhöhung der Resilienz per Default ein Sicherheitszuschlag von 20% eingebaut. Dieser Wert kann mit dem Attribut &#039;&#039;&#039;ctrlBatSocManagementXX-&amp;gt;safetyMargin&#039;&#039;&#039; individuell angepasst werden. &lt;br /&gt;
&lt;br /&gt;
Ist kein PV-Überschuß (mehr) vorhanden / prognostiziert oder das Ladeziel erreicht, erfolgt ein Rückfall der Ladeleistung im Reading Battery_ChargeOptTargetPower_XX auf den  im Attribut &#039;&#039;&#039;setupBatteryDevXX-&amp;gt;pinmax&#039;&#039;&#039; angegebenen Wert. Ist dieser Wert nicht gesetzt, erfolgt der Rückfall auf &amp;quot;Unendlich&amp;quot; (9223372036854775807). &lt;br /&gt;
 &lt;br /&gt;
Im Reading Battery_ChargeOptTargetPower_XX wird der Wert des Parameters &#039;&#039;&#039;setupBatteryDevXX-&amp;gt;pinreduced&#039;&#039;&#039; gesetzt, wenn weniger Ladeleistung als pinreduced berechnet wurde (Einhaltung einer Mindestladeleistung) oder wenn der SoC der Batterie &amp;lt;= [[#Aktivierung_des_Batterie_SOC-_und_Lade-Managements|lowSoC]] beträgt.&lt;br /&gt;
Somit wird die Batterie bei einer Anforderungsladung bei Unterschreitung von lowSoC mit nur wenig Leistung aus dem Grid geladen falls es nötig sein sollte.&lt;br /&gt;
Es ist demzufolge ratsam den optionalen Parameter &#039;&#039;&#039;setupBatteryDevXX-&amp;gt;pinreduced&#039;&#039;&#039; zu setzen, da ansonsten ebenfalls ein Rückfall auf &#039;&#039;&#039;setupBatteryDevXX-&amp;gt;pinmax&#039;&#039;&#039; bzw. &amp;quot;Unendlich&amp;quot; erfolgt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Beide Strategien, optPower und smartPower, setzen die zuvor beschriebene Arbeitsweise um.&lt;br /&gt;
Ergänzend wird bei der Ladestrategie &#039;&#039;&#039;smartPower&#039;&#039;&#039; die generelle Erreichbarkeit des Ladeziels bei der Festlegung der Ladeleistung berücksichtigt. Es führt dazu dass:&lt;br /&gt;
&lt;br /&gt;
* die Ladeleistung im Reading Battery_ChargeOptTargetPower_XX auf einen tendenziell höheren Wert als bei der optPower-Strategie gesetzt wird, wenn/solange das eingestellte Ladeziel als unerreichbar kalkuliert wird&lt;br /&gt;
* bei kalkulierter Erreichbarkeit des Ladeziels der Sicherheitsaufschlag linear absenkend proportional zum Kehrwert des verfügbaren PV-Überschusses auf die Ladeleistung angewendet wird&lt;br /&gt;
&lt;br /&gt;
Der nächste Abschnitt erläutert die smartPower Funktionen etwas eingehender.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
===== smartPower - die zieloptimierte Ladeleistung  =====&lt;br /&gt;
Die hinter smartPower liegende Anpassungslogik wird nachfolgend etwas näher beschrieben.&lt;br /&gt;
Ausgangspunkt ist das Ergbnis einer Ratio-Funktion aus dem (Rest)Tages-PV-Überschuß und benötigter Energie zur Erlangung des Batterie Ladeziels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lineare Interpolation zwischen pinmax und abgesicherter minpower&#039;&#039;&#039;  &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Variablen&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;P&#039;&#039;&#039;: resultierende Leistung.&lt;br /&gt;
* &#039;&#039;&#039;pinmax&#039;&#039;&#039;: maximale Ladeleistung.&lt;br /&gt;
* &#039;&#039;&#039;limpower&#039;&#039;&#039;: Leistungslimit, d.h. Ladeleistungssollwert.&lt;br /&gt;
* &#039;&#039;&#039;r&#039;&#039;&#039;: Verhältnis in Prozent (r = spday·100 / whneed).&lt;br /&gt;
* &#039;&#039;&#039;otpMargin&#039;&#039;&#039;: Prozentwert der Bandbreite, über die die Absenkung linear verläuft (die Steilheit kann mit dem Attributwert ctrlBatSocManagementXX-&amp;gt;safetyMargin im Device eingestellt werden).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Kennlinie der für smartPower eingesetzten Funktion ist stückweise definiert über das Verhältnis Ratio &#039;&#039;𝑟 = spday x 100 / &amp;lt;benötigte Ladeenergie bis Ziel&amp;gt;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
* Für 𝑟 ≤ 100: &#039;&#039;𝑃 = pinmax&#039;&#039;, Interpretation: Es ist viel Bedarf vorhanden bzw. Überschuss ≤ 100 % des Bedarfs → maximal laden.&lt;br /&gt;
* Für 𝑟 ≥ 100 + otpMargin: &#039;&#039;𝑃 = limpower ⋅ (1 + otpMargin / 100 )&#039;&#039;&lt;br /&gt;
* Für 100 &amp;lt; 𝑟 &amp;lt; 100 + otpMargin: lineare Absenkung von &#039;&#039;&#039;P&#039;&#039;&#039; mit zunehmendem &#039;&#039;&#039;r&#039;&#039;&#039; für den Bereich 100 &amp;lt; 𝑟 &amp;lt; 100 + otpMargin. &#039;&#039;&#039;P&#039;&#039;&#039; wird bei 𝑟 = 100 gleich &#039;&#039;&#039;pinmax&#039;&#039;&#039; und bei 𝑟 = 100 + otpMargin gleich &#039;&#039;limpower ⋅ ( 1 + otpMargin/100 )&#039;&#039;, Interpretation: Sobald der Überschuss über den Bedarf hinausgeht (ratio &amp;gt; 100), wird das Ladeleistungslimit schrittweise von pinmax Richtung limpower reduziert; die Reduktion erfolgt gleichmäßig über die Margin-Spanne.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lineare Interpolation und Steigung&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die Differenz &#039;&#039;(pinmax − limpower)&#039;&#039; wird gleichmäßig auf die otpMargin-Prozentpunkte verteilt. Die Steigung der Geraden ist&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
slope = − (pinmax − limpower) / otpMargin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
das heißt die Leistung sinkt um diesen Betrag pro Prozentpunkt von &#039;&#039;&#039;r&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Nach Umformung ist der Zusammenhang wie folgt darstellbar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
𝑃 = pinmax − ( pinmax − limpower) ⋅ ((𝑟 − 100) / otpMargin)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
und ist äquivalent zu&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
𝑃 = pinmax + ( 𝑟 − 100 ) ⋅ slope&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Numerisches Beispiel&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;limpower&#039;&#039;&#039; = 1000 W, &#039;&#039;&#039;pinmax&#039;&#039;&#039; = 3000 W, &#039;&#039;&#039;otpMargin&#039;&#039;&#039; = 20&lt;br /&gt;
* Unterschied = 2000 W, Steigung = −2000/20 = −100 W/%&lt;br /&gt;
* Für &#039;&#039;&#039;r = 105&#039;&#039;&#039;: 𝑃 = 3000 − 2000 ⋅ ( 5 / 20 ) = 3000 − 500 = 2500 W&lt;br /&gt;
* Für &#039;&#039;&#039;r = 120&#039;&#039;&#039; ergibt die Formel den abgesicherten Endwert 1200 W&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Formel sorgt dafür, dass die Zielleistung stufenlos und vorhersehbar reduziert wird, wenn der relative Rest-Überschuss des Tages über 100% steigt, und erreicht bei Ende der otpMargin den geplanten abgesicherten Wert.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Ratio Kennlinie.png|right|thumb|200px|abfallend proportionale Anpassungsfunktion]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In einem grafischen Diagramm stellt sich die abfallend proportionale Anpassungsfunktion der resultierenden Soll-Ladeleistung wie nebenstehend abgebildet dar. Dabei entspricht pow=100 dem jeweiligen pinmax Wert (hier 3000 W). So ist auch pow=0 mit dem abgesicherten Endwert (hier 1200 W) gleichzusetzen. Die Linie verläuft waagerecht bei pinmax solange das das Ratio  r ≤ 100 % und knickt an r == 100 mit steigenden r nach unten. Es verringert sich pow linear von pinmax zu limpower zzgl. otpMargin.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Durch diese Maßnahmen wird eine flexible Lademöglichkeit bis pinmax erreicht, die sich bei unvorhergesehenen Aufklarungen mit starker Sonneneintrahlung bei ansonsten sehr bedeckten Himmel positiv auswirkt. Andererseits wird die Erhöhung der Ladeleistung weiter begrenzt, wenn viel PV-Überschuß in Verbindung mit einer generellen Erreichbarkeit des Ladeziels zum Ende des Tages prognostiziert ist. Man könnte die Ladestrategie &#039;&#039;&#039;smartPower&#039;&#039;&#039; in ihrer Wirkung als einen Mix aus &#039;&#039;&#039;optPower&#039;&#039;&#039; und &#039;&#039;&#039;loadRelease&#039;&#039;&#039; ansehen.&lt;br /&gt;
&lt;br /&gt;
Zusammenfassend ist optPower vorwiegend für die Nutzergruppe geeignet, die eine tendenziell sparsamere Ladeleistung bevorzugen und dafür bereit sind eventuelle &amp;quot;Verluste&amp;quot; in Form von Einspeisung zu akzeptieren. &amp;lt;br&amp;gt;&lt;br /&gt;
Demgegenüber eignet sich das aggressivere smartPower für Anwender, die bei niedrigen PV-Erträgen bewusst das Maximum an Batterieladung anstreben und dafür in Kauf nehmen, dass Ladeleistungen weniger knapp kalkuliert sind. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Unterstützung des Modus &amp;quot;Eigennutzung&amp;quot; bei Hybrid-Wechselrichtern =====&lt;br /&gt;
Viele Hybrid-Wechselrichter verteilen die zur Verfügung stehende PV-Leistung nach folgendem Prioritäten, wenn der (übliche) Modus &amp;quot;Eigennutzung&amp;quot; aktiviert ist:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Nutzung der Leistung zur Deckung des Hausverbrauchs,&lt;br /&gt;
# Nutzung der Leistung zur Ladung des bzw. der angeschlossenen Speicher.&lt;br /&gt;
# Einspeisung der Leistung in das öffentliche Netz.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Da in aller Regel die Leistung, mit der ein angeschlossener Speicher geladen wird, limitiert werden kann, lassen sich die o.g. Priorität bzgl. des Speichers zugunsten einer Überschusseinspeisung aufweichen. Ein entstehender &amp;quot;Überschuss&amp;quot; steht also ggf. nur deshalb zur Verfügung, weil die Ladeleistung des Speichers begrenzt wurde.&lt;br /&gt;
&lt;br /&gt;
Ab Version 1.58.6 bietet SolarForecat die Möglichkeit, prognostizierte Verbräuche nicht mehr komplett bei der Bestimmung der &#039;&#039;optimalen Ladeleistung&#039;&#039; zu berücksichtigen, sondern nur noch zu einem prozentualen Anteil von 0..100 %. Hierzu muss der Attribut-Schlüssel &#039;&#039;&#039;ctrlBatSocManagementXX-&amp;gt;weightOwnUse=&amp;lt;Percentage&amp;gt;&#039;&#039;&#039; entsprechend gesetzt werden. &lt;br /&gt;
&lt;br /&gt;
So führt beispielsweise weightOwnUse=100 dazu, dass bei der Berechnung der optimalen Ladeleistung prognostizierte Verbräuche nicht mehr berücksichtigt werden indem sie bei der Bestimmung des stündlichen PV-Überschusses unberücksichtigt bleiben. Eine derartige Einstellung kann z.B. sinnvoll sein, wenn alle ansonsten täglich laufende Verbraucher zugunsten einer Batterieladung ausgeschaltet werden können.&lt;br /&gt;
&lt;br /&gt;
Ein Wert von zum Beispiel weightOwnUse=30 lässt 30% der stündlichen Verbrauchslast unberücksichtigt, sodass sich der kalkulierte PV-Überschuß pro Stunde um 30% des prognostizierten Verbrauchs erhöht. Da die Berechnung der optimierten Ladeleistung mit dem zur Verfügung stehenden PV-Überschuß gewichtet erfolgt, würde sich die kalkulierte Ladeleistung in den meisten Fällen ebenfalls um einen gewissen Betrag erhöhen sofern andere Faktoren dies nicht verhindern. Das kann beispielweise der Fall sein, wenn die kalkulierte Ladeleistung zu gering ist und automatisch aif mindestens &#039;&#039;&#039;setupBatteryDevXX-&amp;gt;pinreduced&#039;&#039;&#039; angehoben wurde.&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Welche Ladestrategie soll ich wählen? - eine Möglichkeit zur Best-Practice Findung mit Codebeispiel ====&lt;br /&gt;
&lt;br /&gt;
In den vorangegangenen Abschnitten wurden die verschiedenen Möglichkeiten zur Steuerung der Batterieladung und dem SoC vorgestellt. Diese Steuerungsvarianten optimieren die Arbeitweise der Batterie, haben aber jeweils einen eigenen Fokus auch wenn es gewisse Überschneidungen gibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Steuerungsvarianten lassen sich folgendermaßen klassifizieren:&lt;br /&gt;
&lt;br /&gt;
# Steuerung der Batterieladung über eine Ladefreigabe, die durch bestimmte Indikatoren festgelegt wird. Diese Variante ist in [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#PV-Prognose_und_Verbrauch_optimierte_Beladungssteuerung_unter_Berücksichtigung_einer_Wirkleistungsbegrenzung|diesem]] Abschnitt beschrieben.&lt;br /&gt;
# Steuerung der Batterieladung durch eine optimierte maximale Ladeleistung. Diese Variante ist in [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#leistungsoptimierte_Beladungssteuerung_mit_dem_Fokus_geringe_Verlustleistung_und_Verschleiß|diesem]] Abschnitt dargelegt. Zu dieser Variante gehören die Strategien &#039;&#039;optPower&#039;&#039; sowie &#039;&#039;smartPower&#039;&#039;. Die Unterschiede beider Strategien sind ebenfalls in dem verlinkten Abschnitt beschrieben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;&#039;Variante 1.)&#039;&#039;&#039; gibt die Ladung der Batterie frei wenn der (verbleibende) PV-Überschuß des Tages kleiner oder gleich dem Ladungsbedarf der Batterie ist um einen SoC von 100% bzw. den maximal möglichen SoC am Ende des Tages zu erreichen. Dadurch wird die in der Batterie vorhandene freie Kapazität so lange wie möglich der Einhaltung von besonderen Grenzwerten, z.B. des Einspeiselimits (plantControl-&amp;gt;feedinPowerLimit), vorbehalten. Nebeneffekt ist, dass plötzlich und unerwartet auftretende hohe Erzeugungsleistungen in die Batterie geladen werden können und nicht unerwünscht in das öffentliche Netz eingespeist werden. &lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;&#039;Variante 2.)&#039;&#039;&#039; lässt die Batterie kontinuierlich laden, wobei die Ladeleistung auf ein optimiertes Minimum reduziert wird ohne das Ziel, einen maximalen SoC am Tagesende zu erreichen, zu ignorieren. Dadurch wird die Batterie schonend, mit möglichst wenig Verlustleistung und verschleißarm geladen. Die Vorhaltung der freien Kapaziäten der Batterie sind in dieser Variante nicht die Prämisse. Die Einhaltung des gesetzten Enispeiselimits wird auch in dieser Variante beachtet sofern es der Ladezustand der Batterie zulässt. Technisch bedingt kann diese Variante nur ungenügend auf unerwartete PV-Überschüsse reagieren, was zu einer Einspeisung in das öffentliche Netz oder im ungünstigsten Fall zur Abregelung der Anlage führen kann. Mit dem Attribut &#039;&#039;&#039;ctrlBatSocManagementXX-&amp;gt;safetyMargin&#039;&#039;&#039; kann man diesem negativen Aspekt in gewissem Maße entgegenwirken.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ausgehend von diesen unterschiedlichen Optimierungszielen bietet sich die Variante 1.) vorwiegend in den Übergangs- und Wintermonaten an. Durch die beschriebenen Eigenschaften dieser Variante ist bei tendeziell weniger PV-Überschuß über den Tag die Ladung der Batterie komplett freigegeben, wodurch bei plötzlich auftretenden sonnige Abschnitten und Aufklarungen die Batterie sofort mit dem verfügbaren PV-Überschuß geladen wird. Auch eine Einspeisung über das Einspeiselimit hinaus kann verhindert werden. In der übrigen Zeit wird die Ladeleistung durch den verfügbaren PV-Überschuß begrenzt. &lt;br /&gt;
Weiterhin soll der SoC nicht dauerhaft tief absinken und ebenfalls nicht auf einem zu hohen Level verharren was auch einer maximal möglichen Energiespeicherung an sonnigen Tagen entgegenwirken würde.&lt;br /&gt;
In dieser Zeit ist die Nutzung der Kombination von [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Nutzung_des_Batterie_SOC-Management|SoC-Management]] und Variante 1.) wohl am Besten geeignet um die Ziele zu verwirklichen sowie Notreserven in den Batterien vorzuhalten. &lt;br /&gt;
&lt;br /&gt;
In den Sommermonaten hingegen ist üblicherweise sehr viel PV-Energie und Überschuß vorhanden. In dieser Periode würden die Batterien mit sehr hoher Leistung sehr zeitig am Tag vollgeladen. Die Variante 1.) ist im Prinzip ebenfalls gut geeignet den Zeitpunkt der Vollladung hinauszuzögern, jedoch erscheint die Varinte 2.) in dieser Zeit besser geeignet mit einer über den gesamten Tag verteilten moderaten Ladeleistung den Ziel-SoC zu erreichen. Auch diese Variante versucht eine Überschreitung des Einspeiselimits zu verhindern sofern der Ladezustand der Batterie dies ermöglicht.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Codebeispiel zur Steuerung eines in ein Victron System eingebundenen Pylontech Batteriestack via Cerbo GX =====&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;nachfolgende Codebeispiel&#039;&#039;&#039; bietet die Möglichkeit über ein Attribut die Ladevariante auszuwählen, über ein weiteres Attribut die SoC-Steuerung zu aktivieren/deaktivieren, integriert die Ladesteuerung für eine Batterie-Anforderungsladung bei Unterschreitung von ctrlBatSocManagementXX-&amp;gt;lowSoc, und ergänzt eine zellspannungsbasierte Ladestrom-Drosselung (&#039;&#039;&#039;TermVoltageTaper&#039;&#039;&#039;) zum Schutz der Einzelzellen nahe Vollladung.&lt;br /&gt;
&lt;br /&gt;
Die verwendeten Devices werden über eine MQTT Verbindung CerboGX -&amp;gt; FHEM erzeugt und aktualisiert. Der Code wurde mit Venus OS Version v3.72 auf Cerbo GX getestet bzw. mit dieser Version produktiv eingesetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesteuerte Batterieanlage besteht aus:&lt;br /&gt;
* 3 x Victron MultiPlusII 3000/48&lt;br /&gt;
* Steuergerät CerboGX (in FHEM über MQTT eingebunden)&lt;br /&gt;
* einem Batteriestack bestehend aus mehreren Pylontech US3000C (wird durch CerboGX gesteuert und über die separate MQTT-Verbindung als Batteriestack-Device eingebunden)&lt;br /&gt;
* zusätzlich, für TermVoltageTaper: das FHEM-Modul &#039;&#039;&#039;PylonLowVoltage&#039;&#039;&#039;, welches je US3000C-Pack über RS485 die 15 Einzelzellspannungen ausliest (Readings &#039;&#039;cellVoltage_01&#039;&#039; … &#039;&#039;cellVoltage_15&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zur Umschaltung bzw. Auswahl der Ladestrategie und des SoC-Managements werden zwei User-Attribute im SolarForecast Device angelegt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr ... userattr userFn_BatterySoCManagement:Ein,Aus userFn_BatteryLoadManagement:Aus,loadRelease,optPower,smartPower&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Code werden diese Attribute ausgewertet. Das nachfolgende Script vereint folgende Funktionalitäten:&lt;br /&gt;
* die Aktivierung/Deaktivierung des SoC-Managements via Attribut userFn_BatterySoCManagement&lt;br /&gt;
* die Auswahl der Ladestrategie oder Deaktivierung der Ladesteuerung via Attribut userFn_BatteryLoadManagement&lt;br /&gt;
* Integration einer Anforderungsladung bei Signalisierung durch Reading Battery_ChargeRequest_XX&lt;br /&gt;
* eine zellspannungsbasierte Sicherheitsdrosselung des Ladestroms nahe Vollladung (&#039;&#039;&#039;TermVoltageTaper&#039;&#039;&#039;, siehe unten)&lt;br /&gt;
* Generierung von Readings userFn_Victron_GridSetpoint_set und userFn_MPII_MaxChargeCurrent_set zur Dokumentation der eingestellten Soll-Werte, sowie userFn_LoadController_* zur Dokumentation des TermVoltageTaper-Verhaltens&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bei der Nachnutzung des Scripts sind zunächst die &#039;&#039;&#039;Konstanten&#039;&#039;&#039; und die verwendeten Devices (z.B. MQTT2_cerboGX_c0619ab34e08_settings) sowie deren Readings im Block &#039;&#039;&#039;aktuelle Indikatoren&#039;&#039;&#039; anzupassen. Für TermVoltageTaper sind zusätzlich die drei Zellspannungs-Parameter (siehe unten) an die eigene Zellchemie und die eigenen Messwerte anzupassen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Script wird in die Datei &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039; eingetragen und im SolarForecast Attribut &#039;&#039;&#039;ctrlUserExitFn&#039;&#039;&#039; hinterlegt:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr ... ctrlUserExitFn {&lt;br /&gt;
                          ::batLoadMgmnt ($name, &#039;01&#039;);&lt;br /&gt;
                          # ::batLoadMgmnt ($name, &#039;02&#039;);   # optional für eine weitere Batterie &#039;02&#039;&lt;br /&gt;
                          # ::batLoadMgmnt ($name, &#039;0X&#039;);   # optional für weitere Batterien&lt;br /&gt;
                        }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit diesem Script ist der Nutzer in der Lage, das Batterie Lademanagement entsprechend seiner Motivation und gegebenenfalls abhängig von der Jahreszeit umzustellen und das Ergebnis bzw. die Zielerreichung zu testen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Attribut &#039;&#039;&#039;userFn_BatteryLoadManagement&#039;&#039;&#039; selektiert die gewünschte Ladestrategie:&lt;br /&gt;
;Aus: das Lademanagement ist ausgeschaltet&lt;br /&gt;
&lt;br /&gt;
;loadRelease: das Lademanagement Variante 1.) Ladestrategie Ladefreigabe ist aktiviert&lt;br /&gt;
&lt;br /&gt;
;optPower: das Lademanagement Variante 2.) Ladestrategie optimierte Ladeleistung ist aktiviert&lt;br /&gt;
&lt;br /&gt;
;smartPower: das Lademanagement Variante 2.) Ladestrategie zieloptimierte Ladeleistung ist aktiviert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die in SolarForecast eingestellte Ladestrategie (Attributschlüssel &#039;&#039;&#039;ctrlBatSocManagement01-&amp;gt;loadStrategy&#039;&#039;&#039;) wird in dem Steuerungscode in jedem Zyklus aktuell ausgelesen und berücksichtigt.&lt;br /&gt;
&lt;br /&gt;
Hat man die individuell passende Management-Strategie gefunden, bietet sich auch eine automatische (zum Beispiel durch einen Kalender oder Sonnenstand (Elevation) zur Mittagszeit) Umschaltung der Ladestrategie an. Die Unterschreitung der Elevation unter einen bestimmten Wert würde den Beginn des Winterhalbjahres und reverse Überschreitung den Beginn des Sommerhalbjahres kennzeichnen. Entsprechend würde dann die gewünschte Ladestrategie selektiert. Alternativ könnte auch die PV-Überschußprognose für den aktuellen Tag über das Reading &#039;&#039;Today_PVforecast&#039;&#039; für eine Entscheidung bzgl. der Ladestrategie herangezogen werden.&lt;br /&gt;
&lt;br /&gt;
Das SoC-Management kann über das gesamte Jahr aktiviert bleiben, hat jedoch nach bisherigen Erfahrungen nur im Winterhalbjahr eine starke Relevanz.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TermVoltageTaper - Zellschutz nahe Vollladung&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Motivation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ein hoher SoC-Stand allein ist bei LiFePO4-Zellen unkritisch. Problematisch sind vielmehr die bei ungünstigem Ladeverlauf auftretenden hohen &#039;&#039;&#039;Einzelzellspannungen&#039;&#039;&#039; nahe Vollladung – ein globales, SoC-basiertes Lademanagement (wie es SolarForecast über &#039;&#039;Battery_ChargeOptTargetPower_XX&#039;&#039; liefert) kennt die Streuung der Einzelzellen innerhalb eines Batteriestacks nicht und kann daher eine ausbrechende Einzelzelle nicht erkennen. TermVoltageTaper schließt diese Lücke, indem es den von SolarForecast vorgegebenen Ladestrom in der kritischen Endphase anhand der &#039;&#039;&#039;höchsten gemessenen Einzelzellspannung im gesamten Stack&#039;&#039;&#039; begrenzt. Die Lösung basiert auf dem Konzept des Forenusers &#039;&#039;&#039;Parallix&#039;&#039;&#039; (siehe [https://forum.fhem.de/index.php?msg=1359855 #5467] und [https://forum.fhem.de/index.php?msg=1358509 #5199]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Physikalischer Hintergrund: OCV-Kurve und Kniezone&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;&#039;OCV-Kurve&#039;&#039;&#039; (Open Circuit Voltage) beschreibt die Ruhespannung einer Zelle in Abhängigkeit vom SoC – also die Spannung ohne fließenden Strom, nach ausreichender Relaxationszeit. Bei LiFePO4-Zellen verläuft diese Kurve zwischen ca. 20 % und 90 % SoC sehr &#039;&#039;&#039;flach&#039;&#039;&#039;: Die Spannung ändert sich über einen weiten SoC-Bereich kaum, weshalb eine SoC-Schätzung über die Spannung in diesem Bereich unzuverlässig ist (die BMS-SoC-Schätzung basiert daher primär auf Coulomb-Zählung).&lt;br /&gt;
&lt;br /&gt;
Erst kurz vor Vollladung – der &#039;&#039;&#039;Kniezone&#039;&#039;&#039; – steigt die Spannung deutlich steiler an. Genau das macht die Zellspannung in diesem Bereich zu einem empfindlichen, geeigneten Steuersignal: Sie reagiert dort auf SoC- bzw. Ladezustandsänderungen viel stärker als im Flachbereich, und sie macht – anders als der globale Pack-SoC – auch &#039;&#039;&#039;Streuungen zwischen Einzelzellen&#039;&#039;&#039; sichtbar, da jede Zelle einzeln gemessen wird.&lt;br /&gt;
&lt;br /&gt;
[[File:OCV_Kniezone_TermVoltageTaper.png|thumb|420px|OCV-Kurve (grün) und Ladespannung inkl. IR-Drop (orange, gestrichelt) einer LiFePO4-Zelle über dem SoC. Ab ca. 90 % SoC beginnt die Kniezone mit deutlich steilerem Spannungsanstieg. lowerTermVoltage und upperTermVoltage begrenzen den TermVoltageTaper-Regelbereich.]]&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zur reinen Ruhespannung (OCV) liegt bei fließendem Ladestrom noch der &#039;&#039;&#039;IR-Drop&#039;&#039;&#039; (Spannungsabfall am Zell-Innenwiderstand, U_IR = I × R_innen) auf der gemessenen Klemmspannung – daher liegt die tatsächlich gemessene Ladespannung stets etwas über der reinen OCV-Kurve (siehe orangene, gestrichelte Kurve in der Grafik).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Regelparameter&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
TermVoltageTaper arbeitet mit drei zentralen Spannungsparametern (aktuell als lokale Variablen in der Sub definiert, nicht als Attribut):&lt;br /&gt;
&lt;br /&gt;
;LOWER_TERMVOLTAGE (aktuell 3.420 V): Zellspannung, ab der die Drosselung des Ladestroms einsetzt. Der Wert sollte deutlich unterhalb der bei ca. 99 % SoC beobachteten Zellspannung liegen (bei den hier verwendeten US3000C-Packs ca. 3.480 V) und idealerweise empirisch aus den eigenen Log-Daten (Zellspannung über Zeit/SoC während eines vollständigen Ladevorgangs) ermittelt werden.&lt;br /&gt;
&lt;br /&gt;
;UPPER_TERMVOLTAGE (aktuell 3.490 V): Höchste zulässige Zellspannung. Wird sie überschritten, wird der Ladestrom hart auf 0 gesetzt. Der Wert muss mit klarem Sicherheitsabstand unterhalb der BMS-eigenen Überspannungsschutzschwelle liegen (bei US3000C ca. 3.600 V je Zelle).&lt;br /&gt;
&lt;br /&gt;
;VOLTAGE_OFFSET (aktuell 0): IR-Drop-Kompensation für den linearen SoC-Bereich. Bei den in der Praxis auftretenden geringen Lade-C-Raten ist der IR-Drop meist im Bereich der Messauflösung und kann vernachlässigt werden; bei höheren Ladeströmen sollte dieser Wert ggf. SoC-abhängig ergänzt werden.&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 2026-08-09 153126.png|thumb|420px|Arbeitsbereich des TermVoltageTaper (orange eingekreist). Deutlich erkennbar ist die Abregelung von OTP auf &#039;OTP capped&#039; bei Überschreitung der VOLTAGE_OFFSET Rampe. Durch Einsatz der Hysterese UPPER_TERMVOLTAGE_HYST wird ein gleichmäßiger Regelverlauf realisiert.]]&lt;br /&gt;
&lt;br /&gt;
;UPPER_TERMVOLTAGE_HYST (aktuell 0.030 V): Hysterese-Band unterhalb von UPPER_TERMVOLTAGE zur Vermeidung von Oszillationen des Ladestroms. Ohne Hysterese würde eine Proportionalregelung an dieser harten oberen Schwelle zu einem Grenzzyklus neigen: Nach dem Cutoff (current = 0) relaxiert die Zellspannung durch den Wegfall des IR-Drops, unterschreitet dadurch kurzzeitig UPPER_TERMVOLTAGE, der Regler gibt sofort wieder vollen Strom frei, wodurch die Spannung erneut über die Schwelle steigt – der Zyklus beginnt von vorn, oft im Sekundentakt. Mit der Hysterese bleibt ein einmal ausgelöster Cutoff so lange aktiv (Schmitt-Trigger-Verhalten), bis maxCellVolt die niedrigere Freigabeschwelle (UPPER_TERMVOLTAGE − UPPER_TERMVOLTAGE_HYST) tatsächlich unterschreitet. Der aktuelle Zustand (aktiv/inaktiv) wird im Reading &#039;&#039;userFn_LoadController_cutoffActive&#039;&#039; dokumentiert. Der Wert ist ein empirisch ermittelter Startwert; ist die Oszillation trotzdem noch spürbar, kann UPPER_TERMVOLTAGE_HYST schrittweise erhöht werden, auf Kosten einer etwas trägeren Wiederfreigabe nach einem Cutoff. &lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 2026-08-09 184604.png|thumb|420px|Cutoff löst sich im Bereich der Volladung nur selten (OTP Capped steigt bis ca. 2786 W), bis bei übersteigen UPPER_TERMVOLTAGE erneut gecuttet wird. Jedes Mal, wenn sich der Cutoff löst, ist max. Zellenspannung spürbar unter die eingestellte Release-Schwelle (3.460 V) gefallen. Das ist erwünschtes, kontrolliertes Verhalten – kein Bug.]]&lt;br /&gt;
&lt;br /&gt;
Der Taper wirkt als lineare Rampe zwischen &#039;&#039;lowerTermVoltage&#039;&#039; und &#039;&#039;upperTermVoltage&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
current *= 1.0 - (maxCellVolt - lowerTermVoltage) / (upperTermVoltage - lowerTermVoltage);&lt;br /&gt;
current  = 0.0 if maxCellVolt &amp;gt; upperTermVoltage;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ermittlung der maximalen Zellspannung&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
TermVoltageTaper ermittelt &#039;&#039;maxCellVolt&#039;&#039; als Maximum über &#039;&#039;&#039;alle&#039;&#039;&#039; Zellen &#039;&#039;&#039;aller&#039;&#039;&#039; im System vorhandenen &#039;&#039;PylonLowVoltage&#039;&#039;-Devices (bei Parallelschaltung mehrerer US3000C-Packs am gemeinsamen DC-Bus muss die kritischste Einzelzelle über den gesamten Stack hinweg erkannt werden, nicht nur pro Pack). Dabei wird zusätzlich das Alter jedes einzelnen &#039;&#039;cellVoltage_XX&#039;&#039;-Readings geprüft (Parameter &#039;&#039;PYLON_MAXAGE&#039;&#039;, aktuell 300 Sekunden): Ist ein Reading älter, wird sein Wert ignoriert und protokolliert. Werden veraltete Werte gefunden, wird der Ladestrom sicherheitshalber unabhängig vom berechneten &#039;&#039;maxCellVolt&#039;&#039; auf &#039;&#039;batMinChgCurrent&#039;&#039; (aktuell 0) gesetzt – ein Fail-Safe-Verhalten, das eine durch Buskommunikationsprobleme (z. B. RS485-Kollisionen bei mehreren gleichzeitig pollenden Pack-Devices) bedingte Fehlmessung nie unbemerkt in einen zu hohen Ladestrom münden lässt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einbindung in batLoadMgmnt&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
TermVoltageTaper wird als eigenständige Sub aufgerufen und liefert die um den Zellspannungs-Taper gedeckelte Ladeleistung (&#039;&#039;otpCapped&#039;&#039;) zurück:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
my $otpCapped = TermVoltageTaper ($name, $otp, $voltage);&lt;br /&gt;
$otpCapped    = List::Util::min ($otp, $otpCapped);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;otpCapped&#039;&#039; wird anstelle von &#039;&#039;otp&#039;&#039; in die anschließende GridSetpoint-Berechnung übernommen. Damit wirkt der Zellschutz &#039;&#039;&#039;innerhalb desselben Regelpfads&#039;&#039;&#039;, den SolarForecast ohnehin für die PV-Überschuss-basierte Ladesteuerung nutzt: Erreicht &#039;&#039;maxCellVolt&#039;&#039; die Kniezone, sinkt &#039;&#039;otpCapped&#039;&#039;, wodurch automatisch mehr PV-Leistung über den GridSetpoint Richtung Netz/Hausverbrauch statt in die Batterie geleitet wird – ohne zusätzlichen, parallelen Regelkreis.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtiger Hinweis bei DC-gekoppelten Anlagen mit separatem MPPT&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die GridSetpoint-basierte Drosselung wirkt auch dann korrekt, wenn zusätzlich zu den MultiPlusII-Geräten ein direkt am Batterie-DC-Bus hängender MPPT-Solarladeregler im System vorhanden ist. Da MPPT, Batterie und MultiPlusII am selben Gleichstrombus hängen, gilt näherungsweise:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Ladeleistung_Batterie ≈ Leistung_MPPT - Leistung_MultiPlusII&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Erhöht man über den GridSetpoint die vom MultiPlusII Richtung Netz/Hausverbrauch gewandelte Leistung, sinkt automatisch der für die Batterie verbleibende Rest – auch der vom MPPT erzeugte Anteil wird dabei über den MultiPlusII abgeführt und steht folglich nicht mehr für die Batterieladung zur Verfügung. Ein separater Eingriff am MPPT selbst ist für den regulären Taper-Betrieb also nicht erforderlich.&lt;br /&gt;
&lt;br /&gt;
Diese indirekte Drosselung ist zudem verlustfrei: Die abgeregelte Leistung wird nicht am MPPT verworfen (kein Curtailment), sondern produktiv ins Netz oder den Haushalt geleitet.&lt;br /&gt;
&lt;br /&gt;
Die Methode stößt jedoch an eine Grenze, sobald die &#039;&#039;&#039;maximale Einspeiseleistung&#039;&#039;&#039; (Attribut/Reading &#039;&#039;feedinPowerLimit&#039;&#039; bzw. bei Zero-Feed-in-Konfigurationen der Wert 0) bereits ausgeschöpft ist bzw. der GridSetpoint seinen zulässigen negativen Grenzwert (&#039;&#039;neggspmax&#039;&#039;) erreicht hat: In diesem Fall kann die vom MPPT erzeugte Leistung nicht mehr vollständig abgeführt werden, und ein Rest-Ladestrom bleibt trotz &#039;&#039;current = 0&#039;&#039; bestehen. Für den harten Cutoff-Fall (&#039;&#039;maxCellVolt &amp;gt; upperTermVoltage&#039;&#039;) ist dieser Grenzfall relevant und sollte bedacht werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Auswertung / Monitoring&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Beobachtung des Regelverhaltens legt TermVoltageTaper folgende Readings an (mit Event-Erzeugung, &#039;&#039;readingsEndUpdate ($hash, 1)&#039;&#039;, damit FileLog/DbLog diese erfassen können):&lt;br /&gt;
&lt;br /&gt;
;userFn_LoadController_maxCellVolt: aktuell ermittelte maximale Zellspannung im Stack (V)&lt;br /&gt;
&lt;br /&gt;
;userFn_LoadController_maxCellSrc: Pack/Zelle, aus der die maximale Zellspannung stammt (z. B. &#039;&#039;Pylon3:cellVoltage_06&#039;&#039;), hilfreich zur Diagnose bei auffälligem Verhalten einzelner Packs&lt;br /&gt;
&lt;br /&gt;
;userFn_LoadController_otp: vom Modul errechnete optimale Ladeleistung (W) zur Erreichung des Ladeziels ohne Kenntnis der Zellspannungen&lt;br /&gt;
&lt;br /&gt;
;userFn_LoadController_otpCapped: daraus resultierende gedeckelte Ladeleistung (W), die in die weitere GridSetpoint-Berechnung einfließt&lt;br /&gt;
&lt;br /&gt;
;userFn_LoadController_cutoffActive: dokumentiert den Hysterese-Zustand des harten Spannungs-Cutoffs (1 = ausgelöst, Ladeleistung auf 0 W reduziert; 0 = nicht aktiv). &#039;&#039;&#039;Zu beachten:&#039;&#039;&#039; otpCapped kann auch bei cutoffActive=0 den Wert 0 annehmen, nämlich wenn der Stale-Data-Fail-Safe greift (veraltete Zellspannungsdaten) oder wenn die Taper-Rampe rechnerisch auf 0 rundet, ohne dass UPPER_TERMVOLTAGE überschritten wurde. cutoffActive zeigt also ausschließlich, ob speziell der Hysterese-Mechanismus gerade aktiv ist – nicht jede Ursache für otpCapped=0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ein gemeinsamer Plot aus &#039;&#039;userFn_LoadController_maxCellVolt&#039;&#039;, &#039;&#039;userFn_LoadController_current&#039;&#039; bzw. &#039;&#039;userFn_LoadController_otpCapped&#039;&#039; sowie &#039;&#039;Battery_ChargeOptTargetPower_XX&#039;&#039; (als ungedrosselter Referenzwert) zeigt den Taper-Effekt sehr anschaulich: Bis zum Erreichen von &#039;&#039;lowerTermVoltage&#039;&#039; laufen beide Kurven deckungsgleich, danach knickt &#039;&#039;otpCapped&#039;&#039; zunehmend unter den ungedrosselten Zielwert ab, bis bei Erreichen von &#039;&#039;upperTermVoltage&#039;&#039; der harte Cutoff auf 0 greift.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible mw-collapsed&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Code Lademanagement -&amp;gt;&#039;&#039;&#039; &amp;lt;div class=&amp;quot;mw-collapsible-content&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
###############################################################################&lt;br /&gt;
#&lt;br /&gt;
# Save this file as 99_mySolarForecastUtils.pm, and create your own functions&lt;br /&gt;
# in the new file. They are then available in every Perl expression.&lt;br /&gt;
#&lt;br /&gt;
###############################################################################&lt;br /&gt;
 package main;&lt;br /&gt;
 use strict;&lt;br /&gt;
 use warnings;&lt;br /&gt;
 use feature &#039;state&#039;;&lt;br /&gt;
&lt;br /&gt;
 sub&lt;br /&gt;
 mySolarForecastUtils_Initialize($$)&lt;br /&gt;
 {&lt;br /&gt;
   my ($hash) = @_;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
# ab hier eigenen Code eintragen&lt;br /&gt;
&lt;br /&gt;
############################################################################&lt;br /&gt;
#      komplettes Batterie Lademanagement (SOC + Ladeleistung)&lt;br /&gt;
############################################################################&lt;br /&gt;
sub batLoadMgmnt {&lt;br /&gt;
  my $name = shift;&lt;br /&gt;
  my $bn   = shift // &#039;01&#039;;                                            # Batterienummer&lt;br /&gt;
  my $hash = $defs{$name};&lt;br /&gt;
  &lt;br /&gt;
  ## Konstanten&lt;br /&gt;
  ###############  &lt;br /&gt;
  use constant {&lt;br /&gt;
    GSPDEF                 =&amp;gt; 20,                       # Default Einstellung des Grid Setpoint&lt;br /&gt;
    FINDEF                 =&amp;gt; 5000,                     # Default Einspeiselimit&lt;br /&gt;
    MINSOCDEF              =&amp;gt; 10,                       # Default Minimum SoC&lt;br /&gt;
    MAXPLDEF               =&amp;gt; 105,                      # max. Ladestrom (A) für Victron MPII Verbund&lt;br /&gt;
    SYS_VOLTAGE            =&amp;gt; 48,                       # Batterie Systemspannung&lt;br /&gt;
    PYLON_MAXAGE           =&amp;gt; 300,                      # max. erlaubtes Alter (s) eines cellVoltage-Readings&lt;br /&gt;
    LOWER_TERMVOLTAGE      =&amp;gt; 3.420,                    # Zellspannung -&amp;gt; Start Drosselung, deutlich vor 3480 mV bei 99 %&lt;br /&gt;
    UPPER_TERMVOLTAGE      =&amp;gt; 3.490,                    # höchste Zellspannung (oberhalb keine weitere Ladung)&lt;br /&gt;
                                                        # ... (nahe dem vom Hersteller intendierten &amp;quot;voll&amp;quot;-Punkt, mit klarem &lt;br /&gt;
                                                        # ... Sicherheitsabstand zur 3600 mV Schutzschwelle)&lt;br /&gt;
    VOLTAGE_OFFSET         =&amp;gt; 0,                        # Spannungsabfall am Innenwiderstand der Zelle für ein SOC in [20,90] &lt;br /&gt;
                                                        # ... andernfalls VOLTAGE_OFFSET=0&lt;br /&gt;
	UPPER_TERMVOLTAGE_HYST =&amp;gt; 0.030,                    # Hysterese-Band um UPPER_TERMVOLTAGE (V)&lt;br /&gt;
  };&lt;br /&gt;
  &lt;br /&gt;
  my $batsocmgmt  = AttrVal ($name, &#039;userFn_BatterySoCManagement&#039;,  &#039;Aus&#039;);             # Aus / Ein&lt;br /&gt;
  my $batloadmgmt = AttrVal ($name, &#039;userFn_BatteryLoadManagement&#039;, &#039;Aus&#039;);             # Soll: Aus|loadRelease|(opt|smart)Power&lt;br /&gt;
  my $vicsets     = &#039;MQTT2_cerboGX_c0619ab34e08_settings&#039;;                              # Device Victron CerboGX Einstellungen&lt;br /&gt;
  my $batterydev  = &#039;MQTT2_cerboGX_c0619ab34e08_battery&#039;;                               # Device für Pylontech BatteryStack&lt;br /&gt;
  my $ctype       = &#039;Aus&#039;;                                                              # Voreinstellung Steuerungstyp  &lt;br /&gt;
  my $voltage     = ReadingsNum ($batterydev, &#039;DC_Voltage_value&#039;, SYS_VOLTAGE);         # akt. Batteriespannung Bat-Paket (V) &lt;br /&gt;
&lt;br /&gt;
  ## Ladestrategie Ist-Einstellung und Soll-Abgleich&lt;br /&gt;
  ####################################################&lt;br /&gt;
  my $cgbt     = AttrVal ($name, &#039;ctrlBatSocManagement&#039;.$bn, undef);&lt;br /&gt;
  my $strategy = &#039;loadRelease&#039;; &lt;br /&gt;
&lt;br /&gt;
  if ($cgbt) {&lt;br /&gt;
    my $parsed = FHEM::SolarForecast::__parseAttrBatSoc ($name, $cgbt);                 # aktuell gesetzte Strategie ermitteln&lt;br /&gt;
    $strategy  = $parsed-&amp;gt;{loadStrategy} // $strategy;&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  if ($batloadmgmt ne &#039;Aus&#039;) {&lt;br /&gt;
    $ctype = $batloadmgmt;&lt;br /&gt;
	&lt;br /&gt;
    if ($strategy ne $batloadmgmt) {&lt;br /&gt;
      CommandSet (undef, &amp;quot;$name attrKeyVal ctrlBatSocManagement${bn} loadStrategy=$batloadmgmt&amp;quot;); &lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  ## aktuelle Indikatoren&lt;br /&gt;
  ##########################&lt;br /&gt;
  my $finplim = FHEM::SolarForecast::CurrentVal ($name, &#039;feedinPowerLimit&#039;,   FINDEF);  # Limit plantControl-&amp;gt;feedinPowerLimit (W)&lt;br /&gt;
  my $preduce = FHEM::SolarForecast::BatteryVal ($name, $bn, &#039;bpinreduced&#039;, MAXPLDEF);  # reduzierte Ladeleistung aus Bat-Konfig (W)&lt;br /&gt;
  &lt;br /&gt;
  my $surp       = ReadingsNum ($name, &#039;Current_Surplus&#039;,                 0);           # aktueller PV-Überschuß&lt;br /&gt;
  my $bcrq       = ReadingsNum ($name, &#039;Battery_ChargeRequest_&#039;.$bn,      0);           # Notfallladung&lt;br /&gt;
  my $unrestrict = ReadingsNum ($name, &#039;Battery_ChargeUnrestricted_&#039;.$bn, 0);           # Ladefreigabe (1 -&amp;gt; Bat Ladefreigabe)&lt;br /&gt;
  my $curgsp     = ReadingsNum ($vicsets, &#039;GridSetpoint&#039;, GSPDEF);                      # aktuelle Einstellung Grid Setpoint&lt;br /&gt;
  my $otp        = ReadingsNum ($name, &#039;Battery_ChargeOptTargetPower_&#039;.$bn, $preduce);  # optimale Ladeleistung (W)&lt;br /&gt;
  my $actmcc     = ReadingsNum ($vicsets, &#039;MaxChargeCurrent&#039;, 0);                       # akt. maximale Ladestromeinstellung&lt;br /&gt;
  my $load       = MAXPLDEF;                                                            # initialer Soll-Ladestrom MPII (A)&lt;br /&gt;
  my $neggspmax  = -1 * $finplim;&lt;br /&gt;
  &lt;br /&gt;
  my $gridsetpoint = GSPDEF;                                                            # Voreinstellung Grid Setpoint&lt;br /&gt;
  &lt;br /&gt;
  ####################################&lt;br /&gt;
  ##     Battery SoC Management&lt;br /&gt;
  #################################### &lt;br /&gt;
  if ($batsocmgmt eq &#039;Ein&#039;) { &lt;br /&gt;
    my $csoc = ReadingsNum ($vicsets, &#039;MinimumSocLimit&#039;,               MINSOCDEF);     # akt. SoC&lt;br /&gt;
    my $osoc = ReadingsNum ($name,    &#039;Battery_OptimumTargetSoC_&#039;.$bn, MINSOCDEF);     # optimierter Mindest-SoC&lt;br /&gt;
	&lt;br /&gt;
    if ($csoc != $osoc) {&lt;br /&gt;
      CommandSet (undef, &amp;quot;$vicsets MinimumSocLimit $osoc&amp;quot;);&lt;br /&gt;
      Log3 ($name, 3, qq{$name - userFn SoCMgmnt -&amp;gt; MinimumSocLimit in $vicsets set to $osoc %});&lt;br /&gt;
    }                                       &lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  ####################################&lt;br /&gt;
  ##     Battery Lade-Management&lt;br /&gt;
  #################################### &lt;br /&gt;
  &lt;br /&gt;
  #  TermVoltageTaper - Ladestrom-Drosselung anhand Zellspannung (Kniezone)&lt;br /&gt;
  #  Konzept nach Forenuser &#039;Parallix&#039;&lt;br /&gt;
  ############################################################################&lt;br /&gt;
  my $otpCapped = TermVoltageTaper ($name, $otp, $voltage, $bn);                       # OTP eventuell drosseln	&lt;br /&gt;
  $otpCapped    = List::Util::min  ($otp, $otpCapped);                                 # $otp mit der Taper-Grenze deckeln, &lt;br /&gt;
                                                                                       # BEVOR GridSetpoint/Load daraus berechnet werden&lt;br /&gt;
  &lt;br /&gt;
  ## Steuerung nach Ladungsfreigabe&lt;br /&gt;
  ###################################    &lt;br /&gt;
  if ($batloadmgmt eq &#039;loadRelease&#039;) {&lt;br /&gt;
    if (!$unrestrict) {                                                                 # Grid Setpoint absenken bis&lt;br /&gt;
                                                                                        # ... Ladeleistung = 0  &lt;br /&gt;
		$gridsetpoint = GSPDEF - $surp;                                                &lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  ## Steuerung nach optimaler Ladeleistung&lt;br /&gt;
  ##########################################&lt;br /&gt;
  if ($batloadmgmt =~ /(?:opt|smart)Power/xs) {&lt;br /&gt;
    if (!$unrestrict) {                                                                 # Grid Setpoint absenken bis&lt;br /&gt;
        my $gridin = $surp - $otpCapped;                                                # ... Ladeleistung = otpCapped                                               &lt;br /&gt;
		$gridsetpoint = GSPDEF - $gridin;                                               &lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  ## max. Ladestrom der MultiPlusII rechnen&lt;br /&gt;
  ###########################################&lt;br /&gt;
  if ($batloadmgmt ne &#039;Aus&#039;) {&lt;br /&gt;
    $load = $otpCapped / $voltage;                                                      # Ladestrombegrenzung MPII&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  ## Anforderungsladung (überschreibt max. Ladestrom)&lt;br /&gt;
  #####################################################&lt;br /&gt;
  if ($bcrq) {                                                                          # max. Ladeleistung b. Battery_ChargeRequest&lt;br /&gt;
    $ctype = &#039;requestCharging&#039;; &lt;br /&gt;
    &lt;br /&gt;
	if ($surp &amp;lt; $preduce) {&lt;br /&gt;
	  my $p = $preduce;&lt;br /&gt;
	  $load = $p / $voltage;														    # Soll-Ladestrom (A)&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  ## GridSetpoint und max. Ladestrom der MultiPlusII umsetzen&lt;br /&gt;
  #############################################################&lt;br /&gt;
  $gridsetpoint = List::Util::min (GSPDEF, $gridsetpoint);                              # GridSetpoint darf nicht &amp;gt; GSPDEF sein &lt;br /&gt;
  $gridsetpoint = List::Util::max ($neggspmax, $gridsetpoint);                          # GridSetpoint darf nicht &amp;lt; max. Einspeiseleistung sein&lt;br /&gt;
  $gridsetpoint = sprintf &amp;quot;%.0f&amp;quot;, $gridsetpoint;&lt;br /&gt;
  &lt;br /&gt;
  $load      = List::Util::max (0, List::Util::min (MAXPLDEF, $load));                  # clampen&lt;br /&gt;
  $load      = sprintf &amp;quot;%.0f&amp;quot;, $load;&lt;br /&gt;
  &lt;br /&gt;
  if ($curgsp != $gridsetpoint) {                                                       # GridSetpoint setzen&lt;br /&gt;
	  fhem (&amp;quot;set $vicsets GridSetpoint $gridsetpoint&amp;quot;);&lt;br /&gt;
      Log3 ($name, 3, qq{$name - userFn ChargeMgmnt &#039;$ctype&#039; -&amp;gt; GridSetpoint in $vicsets set to $gridsetpoint});&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  if ($load != $actmcc) {&lt;br /&gt;
    CommandSet (undef, &amp;quot;$vicsets MaxChargeCurrent $load&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
    Log3 ($name, 3, qq{$name - userFn ChargeMgmnt &#039;$ctype&#039; -&amp;gt; MaxChargeCurrent MultiPlusII in $vicsets set }.&lt;br /&gt;
                    qq{from old $actmcc A to $load A});&lt;br /&gt;
  }	&lt;br /&gt;
  &lt;br /&gt;
  readingsBeginUpdate ($hash);&lt;br /&gt;
  readingsBulkUpdate  ($hash, &#039;userFn_Victron_GridSetpoint_set&#039;, $gridsetpoint);&lt;br /&gt;
  readingsBulkUpdate  ($hash, &#039;userFn_MPII_MaxChargeCurrent_set&#039;,        $load);&lt;br /&gt;
  readingsEndUpdate   ($hash, 0);&lt;br /&gt;
  &lt;br /&gt;
return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
############################################################################&lt;br /&gt;
#  TermVoltageTaper - Ladestrom-Drosselung anhand Zellspannung (Kniezone)&lt;br /&gt;
#  Idee/Konzept: https://forum.fhem.de/index.php?msg=1358509&lt;br /&gt;
#                https://forum.fhem.de/index.php?msg=1359855&lt;br /&gt;
#  Konzept nach Forenuser &#039;Parallix&#039;&lt;br /&gt;
#  Eingang: OTP, Bat-Spannung&lt;br /&gt;
#  return: gedrosselter OTP &lt;br /&gt;
############################################################################  &lt;br /&gt;
sub TermVoltageTaper {&lt;br /&gt;
  my ($name, $otp, $voltage, $bn) = @_;&lt;br /&gt;
  &lt;br /&gt;
  my $current = $otp / $voltage;&lt;br /&gt;
  my $hash    = $defs{$name};&lt;br /&gt;
  &lt;br /&gt;
  my $termVoltageRange = UPPER_TERMVOLTAGE - LOWER_TERMVOLTAGE;&lt;br /&gt;
  my $releaseVoltage   = UPPER_TERMVOLTAGE - UPPER_TERMVOLTAGE_HYST;&lt;br /&gt;
  my $batMinChgCurrent = 0;&lt;br /&gt;
  &lt;br /&gt;
  state @allPylonDevs;&lt;br /&gt;
  @allPylonDevs = devspec2array (&amp;quot;TYPE=PylonLowVoltage&amp;quot;) if !@allPylonDevs;&lt;br /&gt;
&lt;br /&gt;
  my $maxCellVolt = 0;&lt;br /&gt;
  my $maxCellSrc  = &#039;&#039;;&lt;br /&gt;
  my $staleFound  = 0;&lt;br /&gt;
&lt;br /&gt;
  for my $pd (@allPylonDevs) {&lt;br /&gt;
    for my $cells (1..15) {&lt;br /&gt;
      my $cell = sprintf &amp;quot;%02d&amp;quot;, $cells;&lt;br /&gt;
      my $rn   = &amp;quot;cellVoltage_$cell&amp;quot;;&lt;br /&gt;
      my $age  = ReadingsAge ($pd, $rn, PYLON_MAXAGE + 1);                               # Alter in Sekunden&lt;br /&gt;
      &lt;br /&gt;
	  if ($age &amp;gt; PYLON_MAXAGE) {&lt;br /&gt;
        $staleFound = 1;&lt;br /&gt;
        &lt;br /&gt;
        Log3 ($name, 2, &amp;quot;$name - batTaper[$bn]: $pd $rn is outdated (${age}s) - value will be ignored&amp;quot;)&lt;br /&gt;
             if(FHEM::SolarForecast::askLogtime ($name, &amp;quot;ageIutdated_$pd&amp;quot;, PYLON_MAXAGE - 10)); &lt;br /&gt;
        &lt;br /&gt;
        next;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      my $v = ReadingsNum ($pd, $rn, 0);&lt;br /&gt;
      &lt;br /&gt;
	  if ($v &amp;gt; $maxCellVolt) {&lt;br /&gt;
        $maxCellVolt = $v;&lt;br /&gt;
        $maxCellSrc  = &amp;quot;$pd:$rn&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  # Fail-safe: Wenn veraltete Daten gefunden wurden, sicherheitshalber Strom kappen,&lt;br /&gt;
  # unabhängig vom (evtl. unvollständig ermittelten) $maxCellVolt&lt;br /&gt;
  if ($staleFound) {&lt;br /&gt;
    $current = $batMinChgCurrent;&lt;br /&gt;
    Log3 ($name, 2, &amp;quot;$name - batTaper[$bn]: outdated cell voltage data - set charge current to minimum as a precaution&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  Log3 ($name, 4, &amp;quot;$name - batTaper[$bn]: maxCellVolt=$maxCellVolt V ($maxCellSrc)&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
  ## Taper-Rampe&lt;br /&gt;
  ################&lt;br /&gt;
  if ($maxCellVolt &amp;gt; LOWER_TERMVOLTAGE + VOLTAGE_OFFSET) {&lt;br /&gt;
    $current *= 1.0 - ($maxCellVolt - LOWER_TERMVOLTAGE) / $termVoltageRange;&lt;br /&gt;
    $current = $current &amp;lt; $batMinChgCurrent ? $batMinChgCurrent : $current;&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  ## Hysterese um UPPER_TERMVOLTAGE (Schmitt-Trigger)&lt;br /&gt;
  #######################################################&lt;br /&gt;
  my $cutoffActive = $hash-&amp;gt;{HELPER}{&#039;TVT_CUTOFF&#039;.$bn} // 0;&lt;br /&gt;
&lt;br /&gt;
  if ($cutoffActive) {&lt;br /&gt;
    if ($maxCellVolt &amp;lt;= $releaseVoltage) {&lt;br /&gt;
      $cutoffActive = 0;                                                              # Freigabe: unter Release-Schwelle gefallen&lt;br /&gt;
      Log3 ($name, 4, &amp;quot;$name - batTaper[$bn]: TermVoltageTaper cutoff released (maxCellVolt=$maxCellVolt &amp;lt;= $releaseVoltage)&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    else {&lt;br /&gt;
      $current = 0.0;                                                                 # weiterhin gesperrt, solange über Release-Schwelle&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  elsif ($maxCellVolt &amp;gt; UPPER_TERMVOLTAGE) {&lt;br /&gt;
    $cutoffActive = 1;&lt;br /&gt;
    $current      = 0.0;&lt;br /&gt;
    &lt;br /&gt;
	Log3 ($name, 3, &amp;quot;$name - batTaper[$bn]: TermVoltageTaper cutoff engaged (maxCellVolt=$maxCellVolt &amp;gt; &amp;quot;&lt;br /&gt;
	                .UPPER_TERMVOLTAGE.&amp;quot;)&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  $hash-&amp;gt;{HELPER}{&#039;TVT_CUTOFF&#039;.$bn} = $cutoffActive;&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  $current      = sprintf &amp;quot;%.0f&amp;quot;, $current;&lt;br /&gt;
  my $otpCapped = List::Util::min ($otp, $current * $voltage);&lt;br /&gt;
  &lt;br /&gt;
  readingsBeginUpdate ($hash);&lt;br /&gt;
  readingsBulkUpdate  ($hash, &#039;userFn_LoadController_maxCellVolt&#039;,   $maxCellVolt);&lt;br /&gt;
  readingsBulkUpdate  ($hash, &#039;userFn_LoadController_maxCellSrc&#039;,     $maxCellSrc);&lt;br /&gt;
  readingsBulkUpdate  ($hash, &#039;userFn_LoadController_otpCapped&#039;,       $otpCapped);&lt;br /&gt;
  readingsBulkUpdate  ($hash, &#039;userFn_LoadController_otp&#039;,                   $otp);&lt;br /&gt;
  readingsBulkUpdate  ($hash, &#039;userFn_LoadController_cutoffActive&#039;, $cutoffActive);&lt;br /&gt;
  readingsEndUpdate   ($hash, 0);&lt;br /&gt;
&lt;br /&gt;
return $otpCapped;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
###############################################################################&lt;br /&gt;
# Ende eigener Code&lt;br /&gt;
&lt;br /&gt;
1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== barrierSoC - der Parameter den nicht jeder braucht  ====&lt;br /&gt;
&lt;br /&gt;
Wie bereits hinlänglich beschrieben, aktiviert das Attribut &#039;&#039;&#039;ctrlBatSocManagementXX&#039;&#039;&#039; mit diversen Schlüsseln die Batterie SoC- und Ladesteuerung. Für die alltägliche Nutzung und um schnell sichtbare Ergebnisse zu erzielen, ist die die Verwendung der obligatorischen Schlüssel lowSoc, upSoC und vielleicht noch die Auswahl der gewünschten Ladestrategie zunächst völlig ausreichend. Das Modul stellt für die Batteriesteuerung aber noch einige weitere Schlüssel zu Verfügung, die besondere Anforderungen an die Batteriesteuerung unterstützen. Einer dieser Parameter ist der &#039;&#039;&#039;barrierSoC&#039;&#039;&#039; Schlüssel.&lt;br /&gt;
&lt;br /&gt;
Wird eine der beschriebenen Batterie Ladestrategien &#039;&#039;optPower&#039;&#039; oder &#039;&#039;smartPower&#039;&#039; eingesetzt, wird die Batterieladungsleistung vom aktuell vorhandenen SoC bis zum Ziel-SoC optmiert im Reading Battery_ChargeOptTargetPower_XX bereitgestellt. Dabei wird auch eine eventuell in &#039;&#039;ctrlBatSocManagementXX-&amp;gt;loadTarget&#039;&#039; eingestellte Zielzeit berücksichtigt. Möglicherweise besteht der Wunsch die Batterieladung bis zu einem bestimmten Mindest-SoC so schnell wie möglich aufzuladen um z.B. zügig eine Netzausfallreserve aufzubauen. &lt;br /&gt;
&lt;br /&gt;
Zu diesem Zweck kann der optionale Parameter &#039;&#039;ctrlBatSocManagementXX-&amp;gt;barrierSoC&#039;&#039; verwendet werden. In dem Ladebereich&lt;br /&gt;
&lt;br /&gt;
  lowSoC &amp;lt;= SoC &amp;lt; barrierSoC&lt;br /&gt;
&lt;br /&gt;
kann der User Einfluß auf die berechnete Ladeleistung nehmen und sie ggf. bis zur maximal möglichen Leistung abändern. Das bedeutet alle Manipulationen erfolgen ausschließlich diesem SoC-Bereich.&lt;br /&gt;
Dazu kann dem Parameter mit einer bestimmten Syntax das Änderungsverhalten vorgegeben werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
barrierSoC=XX:&amp;lt;Aktion&amp;gt;:&amp;lt;Wert&amp;gt; oder&lt;br /&gt;
barrierSoC=XX:&amp;lt;Aktion&amp;gt;:&amp;lt;Reading&amp;gt;:&amp;lt;default&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dabei bedeutet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
XX - der Wert von barrierSoC in %. Es gilt lowSoC &amp;lt; XX &amp;lt; maxSoC&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit der &#039;&#039;&#039;&amp;lt;Aktion&amp;gt;&#039;&#039;&#039; wird eine der möglichen Manipulations-Varianten festgelegt:&lt;br /&gt;
&lt;br /&gt;
;max: - das Ladeleistungslimit wird auf setupBatteryDevXX-&amp;gt;pinmax festgelegt&lt;br /&gt;
;set: - das Ladeleistungslimit wird auf einen festen Wert oder Readingswert gesetzt&lt;br /&gt;
;inc: - das Ladeleistungslimit wird um einen festen Wert oder Readingswert erhöht&lt;br /&gt;
;dec: - das Ladeleistungslimit wird um einen festen Wert oder Readingswert verringert&lt;br /&gt;
;prc: - das Ladeleistungslimit wird um einen prozentualen Wert / Readingswert geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Aktion (außer &#039;&#039;max&#039;&#039;) wird auf den angegeben Wert bzw. den Wert des angegebenen Readings angewendet. Das Reading muß im SolarForecast Device enthalten sein. Bei Verwendung eines Readings wird mit &#039;&#039;&amp;lt;default&amp;gt;&#039;&#039; der Standardrückgabewert festgelegt falls das Reading keinen Wert liefert oder nicht vorhanden ist.&lt;br /&gt;
&lt;br /&gt;
Hier sind einige Beispiele für einen barrierSoC. Zur Vereinfachung wird ein barrierSoC von 40 % verwendet und kann natürlich auf einen anderen passenden Wert abgeändert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	barrierSoC=40:max:-                      -&amp;gt; das Ladeleistungslimit wird auf setupBatteryDevXX-&amp;gt;pinmax gesetzt&lt;br /&gt;
	barrierSoC=40:set:&amp;lt;Reading&amp;gt;:&amp;lt;default&amp;gt;    -&amp;gt; das Ladeleistungslimit auf den Wert &amp;lt;Reading&amp;gt; setzen&lt;br /&gt;
	barrierSoC=40:set:1350                   -&amp;gt; das Ladeleistungslimit wird auf 1350 W gesetzt&lt;br /&gt;
	barrierSoC=40:inc:&amp;lt;Reading&amp;gt;:&amp;lt;default&amp;gt;    -&amp;gt; das Ladeleistungslimit um den Wert &amp;lt;Reading&amp;gt; erhöhen&lt;br /&gt;
	barrierSoC=40:inc:200                    -&amp;gt; das Ladeleistungslimit wird um 200 W erhöht&lt;br /&gt;
	barrierSoC=40:dec:&amp;lt;Reading&amp;gt;:&amp;lt;default&amp;gt;    -&amp;gt; das Ladeleistungslimit um den Wert &amp;lt;Reading&amp;gt; verringern&lt;br /&gt;
	barrierSoC=40:dec:100                    -&amp;gt; das Ladeleistungslimit wird um 100 W verringert&lt;br /&gt;
	barrierSoC=40:prc:&amp;lt;Reading&amp;gt;:&amp;lt;default&amp;gt;    -&amp;gt; das Ladeleistungslimit um &amp;lt;Reading&amp;gt; Prozent ändern (+ erhöhen, - verringern)&lt;br /&gt;
	barrierSoC=40:prc:50                     -&amp;gt; das Ladeleistungslimit um 50% ändern (+ erhöhen, - verringern) &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== sequentielle Batterie-Ladung mehrerer Batterien mit lcSlot ====&lt;br /&gt;
&lt;br /&gt;
Der Parameter &#039;&#039;&#039;ctrlBatSocManagementXX-&amp;gt;lcSlot&#039;&#039;&#039; (&amp;quot;load control Slot&amp;quot;) definiert eine Zeitperiode am aktuellen Tag in der die Steuerungslogik für die Batteriesteuerung aktiviert ist. Ist dieser Parameter nicht gesetzt, ist das eingestellte Lademanagement über den gesamten Tag aktiert und wäre identisch mit der Einstellung:&lt;br /&gt;
&lt;br /&gt;
 lcSlot=00:00-23:59&lt;br /&gt;
&lt;br /&gt;
Somit ist die Ladesteuerung per default über den gesamten Tag aktiv.&lt;br /&gt;
&lt;br /&gt;
Durch das Setzen von lcSlot auf einen täglichen Slot wird die Ladesteuerung auf diese Periode eingegrenzt. In der übrigen Zeit ist die Ladung der Batterie freigegeben (Reading Battery_ChargeUnrestricted_XX) bzw. auf die maximal konfigurierte Ladeleistung eingestellt (Reading Battery_ChargeOptTargetPower_XX). Diese Readings können je nach verwendeter Ladestrategie ausgewertet und zur Steuerung der Batterie(n) verwendet werden.  &lt;br /&gt;
Die SoC-Steuerung wird durch die lcSlot-Angabe nicht beeinflusst.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit lcSlot kann zum Beispiel ein sequentielles Laden von mehreren Batterien umgesetzt werden. Nachfolgend wird ein solches Szenario mit drei Batterien  skizziert:&lt;br /&gt;
&lt;br /&gt;
1. die Batterie 1 soll mit voller Leistung geladen werden, die anderen Batterien nur bei weiterem Überschuß. Man würde die jeweiligen &lt;br /&gt;
ctrlBatSocManagementXX-&amp;gt;lcSlot Schlüssel definieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement01 lcSlot=23:00-23:10&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement02 lcSlot=00:00-23:59&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement03 lcSlot=00:00-23:59&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Wie ist der Ablauf: Die Batterie 1 unterliegt keiner Steuerung (nur von 23:00 bis 23:10 als Dummy-Periode). Das Reading Battery_ChargeUnrestricted_01 wird &amp;quot;1&amp;quot; gesetzt, d.h. die Batterie 1 wird zur Ladung uneingeschränkt freigegeben. Die anderen Batterien unterliegen der Steuerung -&amp;gt; Battery_ChargeUnrestricted_02 / 03 sind &amp;quot;0&amp;quot; und sollen nur geladen werden falls ein gesetztes Einspeiselimit überschritten wird.&lt;br /&gt;
&lt;br /&gt;
Ist das Ladeziel der Batterie 1 erreicht, setzt man um die Batterie 2 vollzuladen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement01 lcSlot=00:00-23:59&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement02 lcSlot=23:00-23:10&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement03 lcSlot=00:00-23:59&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Batterien 1 und 3 unterliegen der Steuerung, d.h. Battery_ChargeUnrestricted_01 / 03 haben den Wert &amp;quot;0&amp;quot;. Demgegenüber ist Battery_ChargeUnrestricted_02=1 und soll uneingeschränkt geladen werden.&lt;br /&gt;
&lt;br /&gt;
Ist auch die Batterie 2 voll geladen, würde man das Laden der Batterie 3 aktivieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement01 lcSlot=00:00-23:59&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement02 lcSlot=00:00-23:59&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement03 lcSlot=23:00-23:10&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Setzens via &#039;&#039;&#039;attrKeyVal&#039;&#039;&#039; hat den Vorteil, dass die Zeitfenster-Syntax (Anfangszeit kleiner Endezeit usw.) im Hintergrund peprüft und ggf. ein Fehler zurückgegeben wird, den der Nutzer in seinem Script auswerten kann. Weiterhin werden die Attribute implizit gespeichert sofern global-&amp;gt;autosave nicht explizit auf &amp;quot;0&amp;quot; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Unterstützung eines netzdienlichen Verhaltens ====&lt;br /&gt;
&lt;br /&gt;
Der Steuerungsprozess der Batterieanlage leistet insgesamt einen kleinen Beitrag zur Netzstabilität, indem die Speicherladung in den Zeitraum der meisten prognostizierten Überschußeinspeisung gelegt wird. Im Sommer kann sich dieser Zeitraum in die Zeit nach dem Maxmimum des prognostizierten PV-Überschusses verlagern, wenn auch danach noch genügend Überschußenergie zu Volladung der Batterie prognostiziert wird. In dem Zusammenhang sollte im Attribut &#039;&#039;&#039;plantControl-&amp;gt;feedinPowerLimit&#039;&#039;&#039; ein Einspeiselimit gesetzt werden. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zur Verdeutlichung soll das Beispiel dienen:&lt;br /&gt;
&lt;br /&gt;
* die Batterie ist zu 60% geladen &lt;br /&gt;
* der User hat upSoC=40 eingestellt&lt;br /&gt;
* der User hat maxSoC=90 eingestellt&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Am Vormittag ist genügend Sonne vohanden, das Maximumum der Energie über die Zeit wird aber noch erwartet. &lt;br /&gt;
Zu diesem Zeitpunkt wird das Reading  &#039;&#039;&#039;Battery_ChargeUnrestricted_XX&#039;&#039;&#039; auf den Wert &amp;quot;0&amp;quot; gesetzt. Durch den Nutzer erfolgt daraufhin, zum Beipiel über ein Notify, ein anlagenspezifischer Befehl &amp;quot;Ladestop&amp;quot; an die Batterieanlage. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ab diesem Moment wird:&lt;br /&gt;
&lt;br /&gt;
# die Batterie nicht geladen&lt;br /&gt;
# die erzeugte PV-Energie dem Haushalt zur Verfügung gestellt bzw. der verbleibende Überschuß eingespeist, sofern der Überschuß unterhalb des im Attribut &#039;&#039;&#039;plantControl-&amp;gt;feedinPowerLimit&#039;&#039;&#039; definierten Limits liegt.&lt;br /&gt;
# ein eventuell über dem Limit &#039;&#039;&#039;plantControl-&amp;gt;feedinPowerLimit&#039;&#039;&#039; vorhandener Überschuß in die Batterie geladen und so die Netzlast verringert sowie die Batterie schonend geladen. (dieser Punkt trifft in den Monaten mit wenig PV-Erzeugung eher nicht zu)  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Gleichzeitig liefert die Batterie Energie an das Hausnetz und wird von 60% bis maximal einem SoC-Wert entladen, der durch die [[#Die_dynamische_SOC_Steuerung_mit_Umsetzungsbeispiel|dynamische SOC Steuerung]] bestimmt wird. Dazu muß diese Steuerung natürlich implementiert sein. Sofern der berechnete SoC größer als upSoC ist, wird der maximale Entladungs-SoC auf upSoC gesetzt. &lt;br /&gt;
&lt;br /&gt;
Zusätzlich überprüft das Modul permanent bei jedem Zyklus die Differenz des aktuell vorhandenen SoC zum eingestellten maxSoC.&lt;br /&gt;
Sie soll nicht größer sein um mit dem (noch) zu erwartenden PV-überschuß des Tages der eingestellte maxSoC bzw. dessen Nähe wahrscheinlich erreicht werden kann. &lt;br /&gt;
Sollte der Differenz-Grenzwert erreicht sein, wird &#039;&#039;&#039;Battery_ChargeUnrestricted_XX=1&#039;&#039;&#039; gesetzt und der Nutzer sollte dann über einen geeigneten Befehl seine Anlage in den Modus &amp;quot;Laden&amp;quot; umschalten.&lt;br /&gt;
Dieser Vorgang kann beliebig oft während des Tages alternieren.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Nutzung von batteryTrigger ===&lt;br /&gt;
Ergänzt werden die Möglichkeiten durch das set-Kommando: &lt;br /&gt;
&lt;br /&gt;
 batteryTrigger &amp;lt;1on&amp;gt;=&amp;lt;Wert&amp;gt; &amp;lt;1off&amp;gt;=&amp;lt;Wert&amp;gt; [&amp;lt;2on&amp;gt;=&amp;lt;Wert&amp;gt; &amp;lt;2off&amp;gt;=&amp;lt;Wert&amp;gt; ...] &lt;br /&gt;
&lt;br /&gt;
Das Kommando setzt Triggerpunkte bei Über- bzw. Unterschreitung bestimmter Batterieladungswerte (SoC in %).&lt;br /&gt;
&lt;br /&gt;
Der verwendete SoC wird als resultierender SoC als Summe der aktuellen Ladung aller registrierten Batterie-Geräte im Verhältnis zur installierten Gesamtkapazität gebildet. Das bedeutet, dass alle einzelnen Batterie-Geräte als ein gemeinsamer Cluster betrachtet werden. &lt;br /&gt;
&lt;br /&gt;
Es kann eine beliebige Anzahl von Triggerbedingungen angegeben werden. Xon/Xoff-Bedingungen müssen nicht zwingend paarweise definiert werden.&lt;br /&gt;
Überschreiten die letzten drei SoC-Messungen eine definierte Xon-Bedingung, wird das Reading &#039;&#039;&#039;batteryTrigger_X = on&#039;&#039;&#039; erstellt/gesetzt.&lt;br /&gt;
Unterschreiten die letzten drei SoC-Messungen eine definierte Xoff-Bedingung, wird das Reading &#039;&#039;&#039;batteryTrigger_X = off&#039;&#039;&#039; erstellt/gesetzt.&lt;br /&gt;
&lt;br /&gt;
Der Inhalt der Readings kann durch ein User-Programm oder, bei Erzeugung von entsprechenden Events, mittels notify-Device ausgewertet werden um bei Eintreten eines definierten Ereignisses entsprechende Reaktionen auszulösen. Das kann zum Beispiel die Freigabe eines Heizstabes oberhalb eines bestimmten SOC sein oder ein Entladeverbot der Batterie unterhalb eines SOC-Wertes um Reserven für einen eventuellen Stromausfall zu behalten.&lt;br /&gt;
&lt;br /&gt;
Damit die Batterietrigger dynamisch geändert werden können, ist die Einstellung als Set-Kommando und nicht als Attribut ausgeführt.   &lt;br /&gt;
&lt;br /&gt;
Alle Triggerpunkte können mit dem set-Befehl:&lt;br /&gt;
&lt;br /&gt;
 reset batteryTriggerSet&lt;br /&gt;
&lt;br /&gt;
wieder gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
== Verbrauchersteuerung - Registrieren und visualisieren von Verbrauchern ==&lt;br /&gt;
&lt;br /&gt;
Das Modul gestattet es beliebige Verbraucher (Devices) über die Attribute &#039;&#039;&#039;consumerXX&#039;&#039;&#039; zu registrieren. Durch die Registrierung wird dem Modul der Namen des Devices sowie dessen Eingenschaften durch die Angabe von Schlüssel-Wert Paaren bekannt gemacht.&lt;br /&gt;
&lt;br /&gt;
Nach der Registrierung können die Verbraucher durch das Modul genutzt werden:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* es erfolgt eine Planung der Ein- und Ausschaltzeiten abhängig von der solaren Prognose in Bezug zu den Leistungsdaten des Verbrauchers sowie der anderen registrierten Consumer&lt;br /&gt;
* das Modul kann die Ein- und Ausschaltsteuerung der Consumer übernehmen (optional)&lt;br /&gt;
* die aktuellen Status (Verbrauchsdaten) werden in der Energiefußgrafik dargestellt&lt;br /&gt;
* das Modul lernt mit der Zeit das Verbrauchsverhalten der registrierten Verbraucher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen Verbaucher zu registrieren, wird ein freies &#039;&#039;&#039;consumerXX&#039;&#039;&#039; Attribut, zum Beispiel consumer01, gesetzt.&lt;br /&gt;
&lt;br /&gt;
Die Eigenschaften und das Schaltverhalten wird durch die Angabe der verfügbaren Schlüssel gesteuert. Die Möglichkeiten sind sehr umfangreich. Die nachfolgenden Abschnitte beschreiben die Verwendung am Beispiel oft vorkommender bzw. nachgefragter Sachverhalte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Die Phasen der Verbrauchersteuerung ===&lt;br /&gt;
&lt;br /&gt;
Jeder Zyklus eines Verbrauchers durchläuft im Modul die folgenden Phasen:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Planung&#039;&#039;&#039; der Aktivzeiten des Verbrauchers, d.h. wann der Verbraucher geplant eingeschaltet sowie geplant ausgeschaltet wird und damit der Zyklus beendet wird.&lt;br /&gt;
# &#039;&#039;&#039;Start&#039;&#039;&#039; des Zyklus, d.h. Einschalten des Verbrauchers entsprechend der Planungsdaten sofern weitere, in den Consumer-Schlüsseln definierbare Rahmenbedingungen das Einschalten nicht verhindern (z.B. kein oder zu wenig PV-Energieerzeugung / PV-Überschuss)&lt;br /&gt;
# &#039;&#039;&#039;Permanente Überprüfung von&#039;&#039;&#039; eventuell vorhandenen &#039;&#039;&#039;Interruptbedingungen&#039;&#039;&#039; die den Verbraucher temporär ausschalten und, sofern die Interruptbedingung nicht mehr vorliegt, den Verbraucher wieder einschalten und so den gestarteten Zyklus fortsetzen.&lt;br /&gt;
#  &#039;&#039;&#039;Beendigung&#039;&#039;&#039; der Zyklus. Die Beendigung erfolgt entweder (normalerweise) wenn die geplante Endezeit der Zyklus erreicht ist oder eine optionale Endebedingung erfüllt ist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Steuerung der Phasen ====&lt;br /&gt;
Der Ablauf der Phasen kann durch verschiedene Schlüssel-Wert Paare beeinflusst und gesteuert werden.&lt;br /&gt;
&lt;br /&gt;
Mit dem optionalen Schlüssel &#039;&#039;&#039;swoncond&#039;&#039;&#039; kann eine &#039;&#039;&#039;zusätzliche externe Bedingung&#039;&#039;&#039; definiert werden um den Einschaltvorgang des Consumers freizugeben. Ist die Bedingung (Regex) nicht erfüllt, erfolgt kein Einschalten des Verbrauchers auch wenn die sonstigen Voraussetzungen wie Zeitplanung, on-Schlüssel, auto-Mode und aktuelle PV-Leistung gegeben sind. Es erfolgt somit eine &#039;&#039;&#039;UND-Verknüpfung&#039;&#039;&#039; des Schlüssels swoncond mit den Planungsdaten und weiteren Einschaltbedingungen.&lt;br /&gt;
&lt;br /&gt;
Der optionale Schlüssel &#039;&#039;&#039;swoffcond&#039;&#039;&#039; definiert eine &#039;&#039;&#039;vorrangige Ausschaltbedingung&#039;&#039;&#039; (Regex). Sobald diese Bedingung erfüllt ist, wird der Consumer ausgeschaltet auch wenn die geplante Endezeit (consumerXX_planned_stop) noch nicht erreicht ist (&#039;&#039;&#039;ODER-Verknüpfung&#039;&#039;&#039;). Weitere Bedingungen wie off-Schlüssel und auto-Mode müssen zum automatischen Ausschalten erfüllt sein.&lt;br /&gt;
&lt;br /&gt;
Mit dem optionalen Schlüssel &#039;&#039;&#039;interruptable&#039;&#039;&#039; kann während der geplanten Einschaltzeit eine automatische Unterbrechung sowie Wiedereinschaltung des Verbrauchers vorgenommen werden. Der Verbraucher wird temporär ausgeschaltet (interrupted) und wieder eingeschaltet (continued) wenn die Interrupt-Bedingung nicht mehr vorliegt. Die verbleibende Laufzeit wird durch einen Interrupt nicht beeinflusst! &lt;br /&gt;
&lt;br /&gt;
Der Schlüssel &#039;&#039;&#039;power&#039;&#039;&#039; gibt die nominale Leistungsaufnahme des Verbrauchers gemäß seines Datenblattes an. Dieser Wert wird verwendet um die Schaltzeiten des Verbrauchers zu planen und das Schalten in Abhängigkeit des tatsächlichen PV-Überschusses zum Einplanungszeitpunkt zu steuern. Ist &#039;&#039;&#039;power=0&#039;&#039;&#039; gesetzt, wird der Verbraucher unabhängig von einem zum Zeitpunkt des Zyklus-Start eventuell nicht ausreichend vorhandenem PV-Überschuss wie geplant eingeschaltet und somit der Zyklus gestartet.&lt;br /&gt;
&lt;br /&gt;
Durch die Schlüssel &#039;&#039;&#039;notbefore&#039;&#039;&#039; und &#039;&#039;&#039;notafter&#039;&#039;&#039; kann der Startzeitpunkt des Verbrauchers so gesteuert werden, dass der Start des Zyklus nicht vor bzw. nach der angegebenen Zeit eingeplant wird. Diese Steuerung bezieht sich auf die &#039;&#039;Planung&#039;&#039;, d.h. der eigentliche Start des Verbrauchers kann sich unter Umständen durch vorhandene Rahmenbedingungen verzögern. &lt;br /&gt;
&lt;br /&gt;
Der Schlüssel &#039;&#039;&#039;mintime&#039;&#039;&#039; legt die geplanten Einschaltzeit, d.h. die Laufzeit des Zyklus fest. Der Name &#039;&#039;&#039;mintime&#039;&#039;&#039; ist nicht als MInimum-Zeit zu deuten, sondern beschreibt die angegebene Zeit in Minuten die der Zyklus dauern soll.&lt;br /&gt;
&lt;br /&gt;
Dieser Schlüssel ist optional, da sich die Standard-Laufzeit des Verbrauchers von dessen Typ abgeleitet wird. Diese Standard Laufzeiten sind:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|dryer&lt;br /&gt;
|90 Minuten&lt;br /&gt;
|-&lt;br /&gt;
|fridge&lt;br /&gt;
|1440 Minuten&lt;br /&gt;
|-&lt;br /&gt;
|bev&lt;br /&gt;
|600 Minuten&lt;br /&gt;
|-&lt;br /&gt;
|dehydrator&lt;br /&gt;
|600 Minuten&lt;br /&gt;
|-&lt;br /&gt;
|heatpump&lt;br /&gt;
|Sonderfall&lt;br /&gt;
&lt;br /&gt;
KI-Prognose (ab V2.0.0) beachten &lt;br /&gt;
|-&lt;br /&gt;
|dishwasher&lt;br /&gt;
|180 Minuten&lt;br /&gt;
|-&lt;br /&gt;
|washingmachine&lt;br /&gt;
|120 Minuten&lt;br /&gt;
|-&lt;br /&gt;
|heater&lt;br /&gt;
|240 Minuten&lt;br /&gt;
|-&lt;br /&gt;
|charger&lt;br /&gt;
|120 Minuten&lt;br /&gt;
|-&lt;br /&gt;
|other&lt;br /&gt;
|60 Minuten&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Automatiksteuerung der Verbraucher ===&lt;br /&gt;
&lt;br /&gt;
==== Was ist die Automatiksteuerung? ====&lt;br /&gt;
&lt;br /&gt;
Die Automatiksteuerung ist der zentrale Mechanismus, mit dem SolarForecast einen Verbraucher (Consumer) eigenständig anhand von PV-Überschuss, Planungsdaten und den konfigurierten Rahmenbedingungen (Zeitfenster, Sperrzeiten, Prioritäten etc.) ein- und ausschaltet. Sie ist die Voraussetzung dafür, dass ein Consumer überhaupt automatisch geschaltet werden kann.&lt;br /&gt;
&lt;br /&gt;
Ist die Automatik für einen Consumer &#039;&#039;&#039;deaktiviert&#039;&#039;&#039;, greift SF nicht in dessen Schaltzustand ein – der Consumer kann dann ausschließlich manuell (per Schalter am Gerät, per Set-Befehl, über eine andere Automatisierung etc.) bedient werden.&lt;br /&gt;
&lt;br /&gt;
Ist die Automatik &#039;&#039;&#039;aktiviert&#039;&#039;&#039;, übernimmt SolarForecast die Kontrolle über den Consumer im Rahmen der jeweiligen Planungs- und Überschusslogik (Modus &amp;lt;code&amp;gt;can&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;must&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;mustNot&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Konfiguration: das Attribut &amp;lt;code&amp;gt;consumerXX-&amp;gt;auto&amp;lt;/code&amp;gt; ==== &lt;br /&gt;
&lt;br /&gt;
Für jeden Consumer wird über das consumerspezifische Attribut-Element &amp;lt;code&amp;gt;consumerXX-&amp;gt;auto&amp;lt;/code&amp;gt; festgelegt, &#039;&#039;&#039;welches Reading&#039;&#039;&#039; des Consumer-Devices die Automatikfreigabe liefert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
auto=&amp;amp;lt;Readingname&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
auto=Automatik&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wirkung:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Das referenzierte Reading wird von SolarForecast bei jedem Zyklus ausgelesen.&lt;br /&gt;
* Wert &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (bzw. jeder als &amp;quot;wahr&amp;quot; interpretierbare Wert) → Automatik &#039;&#039;&#039;aktiv&#039;&#039;&#039;: SolarForecast darf den Consumer schalten.&lt;br /&gt;
* Wert &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; → Automatik &#039;&#039;&#039;inaktiv&#039;&#039;&#039;: SolarForecast plant zwar ggf. weiter im Hintergrund, führt aber &#039;&#039;&#039;keine Schaltbefehle&#039;&#039;&#039; aus.&lt;br /&gt;
* Ist kein &amp;lt;code&amp;gt;auto&amp;lt;/code&amp;gt;-Schlüssel gesetzt, verhält sich der Consumer standardmäßig so, als wäre die Automatik dauerhaft aktiv (Default &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Zusammenspiel von Automatik-Reading und grafischem Schalter im Consumer-Panel ====&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2026-08-02 220921.png|right|thumb|400px|Automatik-Schalter im Consumer Panel]]&lt;br /&gt;
&lt;br /&gt;
Im Consumer-Panel (Bereich &amp;quot;Consumer Legend&amp;quot;) wird für jeden Consumer ein Schieberegler/Schalter für die Automatik angezeigt. Dieser Schalter ist &#039;&#039;&#039;keine eigenständige SolarForecast-interne Logik&#039;&#039;&#039;, sondern lediglich eine grafische Repräsentation des unter &amp;lt;code&amp;gt;auto&amp;lt;/code&amp;gt; hinterlegten Readings:&lt;br /&gt;
&lt;br /&gt;
* Betätigung des Schalters im Panel setzt den Wert des referenzierten Readings am zugeordneten Device auf 0 oder 1.&lt;br /&gt;
* SolarForecast liest ausschließlich dieses Reading aus – nicht den Schalterzustand selbst. Der Schalter ist also nur die Benutzeroberfläche für das Reading, keine separate Speicherstelle.&lt;br /&gt;
* Wird das Reading auf anderem Weg verändert (z.B. durch eine andere Automatisierung, ein Notify, etc.), zeigt der Panel-Schalter dies beim nächsten SolarForecast-Zyklus entsprechend an – die Wirkung auf SolarForecast ist identisch, unabhängig davon, auf welchem Weg das Reading gesetzt wurde.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Praktisch bedeutet das:&#039;&#039;&#039; Ob der Automatikmodus über den Panel-Schalter, ein Skript oder eine andere FHEM-Automatisierung umgeschaltet wird, spielt für SolarForecast keine Rolle – entscheidend ist ausschließlich der aktuelle Wert des konfigurierten Readings.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Manuelle Eingriffe während aktiver Automatik ====&lt;br /&gt;
&lt;br /&gt;
SolarForecast erkennt, wenn ein Consumer &#039;&#039;&#039;außerhalb der eigenen Schaltlogik&#039;&#039;&#039; geschaltet wird (z.B. per Schalter an der Steckdose, per App, durch eine andere Automatisierung), während die Automatik für diesen Consumer aktiv ist. Ein solcher externer Schaltvorgang wird im consumerXX-Reading mit dem Hinweis &amp;lt;code&amp;gt;von extern umgeschaltet&amp;lt;/code&amp;gt; protokolliert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Grundprinzip:&#039;&#039;&#039; SolarForecast unterbricht in diesem Fall bewusst seine eigene Schaltungslogik für diesen Consumer, um nicht störend in eine manuelle Aktion einzugreifen (z.B. laufende Wartung, kurzzeitiges Nachladen eines Wäschestücks in eine bereits laufende Waschmaschine, etc.).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Fall 1: Automatik wird aus- und wieder eingeschaltet ===== &lt;br /&gt;
&lt;br /&gt;
Wird die Automatik für einen Consumer &#039;&#039;&#039;bewusst deaktiviert und anschließend wieder aktiviert&#039;&#039;&#039; (Flanke AUS → EIN am &amp;lt;code&amp;gt;auto&amp;lt;/code&amp;gt;-Reading), so übernimmt SolarForecast die Kontrolle &#039;&#039;&#039;in jedem Fall wieder&#039;&#039;&#039; – unabhängig davon, ob der Schaltzustand des Consumers zwischenzeitlich manuell verändert wurde oder nicht, und unabhängig davon, ob dieser Zustand vor der Reaktivierung wiederhergestellt wurde.&lt;br /&gt;
&lt;br /&gt;
Dieser Vorgang wird im Consumer-Reading mit dem Hinweis &amp;lt;code&amp;gt;Automatik fortgesetzt&amp;lt;/code&amp;gt; quittiert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Merksatz:&#039;&#039;&#039; Die bewusste Reaktivierung der Automatik ist der eindeutigste Weg, die Kontrolle zuverlässig wieder an SF zu übergeben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Fall 2: Automatik bleibt durchgehend aktiv, Ursprungszustand wird wiederhergestellt ===== &lt;br /&gt;
&lt;br /&gt;
Bleibt die Automatik durchgehend &#039;&#039;&#039;aktiviert&#039;&#039;&#039; und der Consumer wird manuell geschaltet, erkennt SolarForecast automatisch, wenn der &#039;&#039;&#039;Schaltzustand vor der manuellen Aktion wiederhergestellt&#039;&#039;&#039; wird – also z.B.:&lt;br /&gt;
&lt;br /&gt;
* Consumer war automatisch ein → manuell aus → manuell wieder ein&lt;br /&gt;
* Consumer war automatisch aus → manuell ein → manuell wieder aus&lt;br /&gt;
&lt;br /&gt;
In diesem Fall übernimmt die Automatik ebenfalls wieder selbstständig, sobald der Ursprungszustand erreicht ist – auch ohne dass die Automatik zwischenzeitlich deaktiviert wurde. Auch dieser Vorgang wird mit &amp;lt;code&amp;gt;Automatik nach Rundlauf fortgesetzt&amp;lt;/code&amp;gt; quittiert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig:&#039;&#039;&#039; Wird der Ursprungszustand &#039;&#039;&#039;nicht&#039;&#039;&#039; wiederhergestellt (z.B. Consumer war automatisch ein und wird manuell aus geschaltet, bleibt dann aber dauerhaft aus), bleibt der Consumer zunächst planungstechnisch &amp;quot;eingefroren&amp;quot; – siehe folgenden Abschnitt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Fall 3: Consumer bleibt manuell abweichend vom Automatikstatus stehen ===== &lt;br /&gt;
&lt;br /&gt;
Wird ein Consumer manuell geschaltet und der neue Zustand &#039;&#039;&#039;nicht&#039;&#039;&#039; wieder in den Ursprungszustand zurückgeführt (z.B. manuell dauerhaft ausgeschaltet, während die Automatik ihn eigentlich eingeschaltet lassen würde), bleibt der Consumer zunächst &#039;&#039;&#039;nicht&#039;&#039;&#039; unter aktiver Kontrolle der Automatik.&lt;br /&gt;
&lt;br /&gt;
Die Automatik übernimmt in diesem Fall &#039;&#039;&#039;trotzdem wieder&#039;&#039;&#039;, sobald sie den Consumer im Rahmen ihrer normalen Zyklen einmal selbst &amp;quot;berührt&amp;quot; – am häufigsten durch eine kurzzeitige Unterbrechung mangels ausreichendem PV-Überschuss. Sobald dieser interne Abgleich stattgefunden hat, ist der intern gespeicherte Schaltzustand wieder deckungsgleich mit dem tatsächlichen physischen Zustand, und die Automatik behandelt den Consumer ab diesem Zeitpunkt wieder vollständig regulär – inklusive automatischem Wiedereinschalten bei ausreichendem Überschuss.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Praktische Konsequenz:&#039;&#039;&#039; Bei Consumern mit häufig schwankendem Überschuss (typisch bei wechselhafter Bewölkung oder gleichzeitig aktiven anderen Verbrauchern) kann dieser interne Abgleich vergleichsweise schnell erfolgen – oft innerhalb weniger Minuten. Ein manuelles dauerhaftes Abschalten sollte deshalb &#039;&#039;&#039;nicht ausschließlich&#039;&#039;&#039; auf diesem impliziten Mechanismus beruhen, sondern nötigenfalls durch Deaktivieren der Automatik (siehe Fall 1) oder eine geeignete Ausschlussbedingung (z.B. &amp;lt;code&amp;gt;swoffcond&amp;lt;/code&amp;gt;) zuverlässig gegen ungewollten Wiederanlauf abgesichert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Best Practice ====&lt;br /&gt;
&lt;br /&gt;
Für ein zuverlässiges und nachvollziehbares Verhalten der Automatiksteuerung gilt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Kurzzeitige manuelle Eingriffe&#039;&#039;&#039; (z.B. kurz nachschauen, ein Wäschestück nachlegen) bei &#039;&#039;&#039;aktiver&#039;&#039;&#039; Automatik sind unproblematisch, solange der Ursprungszustand danach wiederhergestellt wird – die Automatik erkennt dies und läuft danach normal weiter.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Soll ein Consumer dauerhaft und zuverlässig von der Automatik ausgenommen werden&#039;&#039;&#039; (z.B. für längere Wartungsarbeiten, bewusstes Stilllegen), empfiehlt es sich, die Automatik für diesen Consumer &#039;&#039;&#039;explizit zu deaktivieren&#039;&#039;&#039; (&amp;lt;code&amp;gt;auto&amp;lt;/code&amp;gt;-Reading auf &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; setzen), statt sich auf einen dauerhaft abweichenden Schaltzustand zu verlassen. Nur so ist sichergestellt, dass SolarForecast in der Zwischenzeit keine Schaltbefehle ausführt.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Soll die Kontrolle anschließend zuverlässig wieder an SolarForecast übergeben werden&#039;&#039;&#039;, die Automatik bewusst wieder aktivieren (Flanke AUS → EIN). Dies ist der eindeutigste und sofortige Weg, unabhängig vom aktuellen Schaltzustand des Consumers.&lt;br /&gt;
&lt;br /&gt;
* Für Consumer, die &#039;&#039;&#039;dauerhaft manuell abweichend&#039;&#039;&#039; von der Automatik-Empfehlung bleiben sollen, obwohl die Automatik selbst aktiv bleibt, empfiehlt sich zusätzlich eine passende &amp;lt;code&amp;gt;swoffcond&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;swoncond&amp;lt;/code&amp;gt;-Bedingung, um ein unbeabsichtigtes Wiedereinschalten durch den in Fall 3 beschriebenen impliziten Abgleich zuverlässig zu verhindern.&lt;br /&gt;
&lt;br /&gt;
* Der Status jedes Schaltvorgangs (inkl. &amp;quot;extern umgeschaltet&amp;quot;- und &amp;quot;Rundlauf fortgesetzt&amp;quot;-Hinweise) ist jederzeit im jeweiligen &amp;lt;code&amp;gt;consumer&amp;amp;lt;XX&amp;amp;gt;&amp;lt;/code&amp;gt;-Reading im Feld &amp;lt;code&amp;gt;info=&amp;lt;/code&amp;gt; nachvollziehbar.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Der Verbraucher wurde nicht gestartet obwohl die Startzeit der Einplanung erreicht wurde ===&lt;br /&gt;
&lt;br /&gt;
Wenn die Startzeit des Consumers entsprechend der Einplanung erreicht oder überschritten ist, wird der Consumer eingeschaltet wenn die weiteren Voraussetzungen wahr sind:&lt;br /&gt;
&lt;br /&gt;
* es ist aktuell ein PV-Überschuss vorhanden und der PV-Überschuss deckt die kalkulierten Leistungsaufnahme des Verbrauchers ab. Mit den Schlüsseln &#039;&#039;&#039;power&#039;&#039;&#039; und &#039;&#039;&#039;spignorecond&#039;&#039;&#039; kann die Einschaltung trotz fehlendem PV-Überschuss ermöglicht werden. &lt;br /&gt;
&lt;br /&gt;
* die Angabe im Schlüssel &#039;&#039;&#039;swoncond&#039;&#039;&#039; ist wahr (sofern gesetzt)&lt;br /&gt;
&lt;br /&gt;
* das Schalten ist über den Schlüssel &#039;&#039;&#039;auto&#039;&#039;&#039; freigegeben (sofern gesetzt)&lt;br /&gt;
&lt;br /&gt;
* im Schlüssel &#039;&#039;&#039;on&#039;&#039;&#039; ist ein valides Einschaltkommando hinterlegt&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sind diese zusätzlichen Bedingungen nicht erfüllt, erfolgt kein Start des eingeplanten Zyklus. Der Verbraucher verbleibt in diesem Fall weiterhin im Status &#039;&#039;planned&#039;&#039; oder &#039;&#039;suspended&#039;&#039;. Die Startbedingungen werden regelmäßig reviewed und der Consumer gestartet sobald alle Startbedingungen wahr sind bzw. Start verhindernde Bedingungen entfallen sind. &lt;br /&gt;
&lt;br /&gt;
Dieser Vorgang erfolgt bis das geplante Ende des Verbaucherzyklus erreicht ist oder die Bedingung im Schlüssel &#039;&#039;&#039;swoffcond&#039;&#039;&#039; zutrifft. Sobald die Bedingung im Schlüssel &#039;&#039;&#039;swoffcond&#039;&#039;&#039; wahr ist, wird der gesamte Planungszyklus des Consumers beendet.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kann manuell / automatisiert in den Planungszyklus eines Verbrauchers eingegriffen werden? ===&lt;br /&gt;
&lt;br /&gt;
Die Einplanung und die darauf aufbauenden Schaltprozesse laufen gemäß den hinterlegten Schlüsseloptionen im Modul automatatisch ab ohne dass ein Eingriff durch den Anwender erfolgen muß.&lt;br /&gt;
&lt;br /&gt;
Dennoch kann es gewünscht sein eine Neuplanung oder eine Sofortplanung eines Consumers vorzunehmen weil der Bedarf dazu besteht. Zu diesem Zweck stehen die Set-Kommandos&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* consumerNewPlanning &lt;br /&gt;
&lt;br /&gt;
* consumerImmediatePlanning &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
zur Verfügung. &lt;br /&gt;
Beide Befehle initiieren die Consumer-Neuplanung, wobei mit dem Befehl &#039;&#039;consumerImmediatePlanning&#039;&#039; die eventuell im consumerXX Attribut gesetzten Schlüssel notbefore, notafter bzw. mode werden nicht beachtet werden. Dagenen beachtet der Befehl &#039;&#039;consumerNewPlanning&#039;&#039; alle definierten Schlüsseloptionen und dient gewöhnlich dazu einen abgeschlossenen Verbraucherzyklus wiederholt ausführen zu lassen weil die aktuelle Witterungslage dazu geeignet ist. &lt;br /&gt;
&lt;br /&gt;
Ein Anwendungsbeispiel dafür ist zum Beispiel die Ausführung von mehreren Waschmaschinen-Zyklen an einem langen, sonnigen Sommertag.&lt;br /&gt;
Diese beiden Set-Befehle können zum Beispiel über ein auf einen Schalter/Taster reagierendes Notify oder DOIF Device ausgeführt werden. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Registrierung eines Verbrauchers mit getrennten Geräten für Messung und Schalten ===&lt;br /&gt;
&lt;br /&gt;
Es existieren in FHEM Geräte, die über verschiedene Kanäle für unterschiedliche Aufgaben verfügen. Diese Kanäle werden jeweils in einem gesonderten Device abgebildet. HomeMatic oder readingsProxy sind Beispiele für solche Varianten.&lt;br /&gt;
&lt;br /&gt;
Um solche Verbraucher einzubinden gibt es im consumerXX Attribut den Schlüssel &#039;&#039;&#039;switchdev&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Bei der Registrierung gibt man als Consumerdevice das Gerät für die Messung an und im Schüssel switchdev das entsprechende FHEM-Device, welches für die Schaltvorgänge benutzt wird. &lt;br /&gt;
Ist switchdev angegeben, beziehen sich die weiteren Schlüssel on, off, swstate, auto und asynchron auf dieses Gerät.&lt;br /&gt;
&lt;br /&gt;
In dem nachfolgenden Beispiel (Homematic) ist &#039;&#039;eg.az.fridge_Pwr&#039;&#039; FHEM Device für die Energiemessung. Die Schlüssel &#039;&#039;pcurr&#039;&#039; und &#039;&#039;etotal&#039;&#039; geben Readings in diesem Device an damit SolarForecast den Verbrauch und die Energiemengen auslesen kann. Demgegenüber ist im Schlüssel &#039;&#039;switchdev&#039;&#039; das zugehörige Schalter-Device der Kombination angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
eg.az.fridge_Pwr&lt;br /&gt;
type=noSchedule switchdev=eg.az.fridge_Sw power=0 icon=fridge pcurr=power:W:5 etotal=energyCalc:Wh &lt;br /&gt;
swstate=state:on:off auto=automatic&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Registrierung von Verbrauchern ohne Zeitplanung und aktivem Schalten ===&lt;br /&gt;
Manchmal besteht der Wunsch, Verbraucher in SolarForecast zu integrieren um lediglich folgende Sachverhalte abzubilden:&lt;br /&gt;
&lt;br /&gt;
* Visualisierung des Schaltstatus in der Consumer Legende und/oder der Energieflußgrafik&lt;br /&gt;
* Darstellung des aktuellen Energieverbrauchs in der Energieflußgrafik&lt;br /&gt;
* Erfassung der (externen) Schaltzeiten, d.h. der Zeiten der Gerätenutzung sowie der Verbrauchsdaten um deren Einfluß bei den Planungszeiten anderer Geräte durch SolarForecast berücksichtigen zu lassen&lt;br /&gt;
&lt;br /&gt;
In solchen Fällen werden bei der Registrierung die Schlüssel &#039;&#039;swstate, pcurr&#039;&#039; und &#039;&#039;etotal&#039;&#039; zur Erfassung der Schaltzustände und der Energieverbrauchs angegeben, jedoch zur Verhinderung der Zeitplanung durch SolarForecast der Schlüssel &#039;&#039;&#039;type=noSchedule&#039;&#039;&#039; gesetzt sowie die Schlüssel &#039;&#039;on&#039;&#039; und &#039;&#039;off&#039;&#039; &#039;&#039;&#039;nicht&#039;&#039;&#039; gesetzt.&lt;br /&gt;
&lt;br /&gt;
Das nachfolgende Beispiel zeigt eine mögliche Registrierung eines Zwischensteckers (Shelly) zur Erfassung der Daten eines Gefrierschrankes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Shelly.shellyplug4&lt;br /&gt;
type=noSchedule power=65 asynchron=1&lt;br /&gt;
icon=gefrierschrank &lt;br /&gt;
swstate=state:.*on.*:.*off.* &lt;br /&gt;
pcurr=relay_0_power:W:5 etotal=relay_0_energy_Wh:Wh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Sonderregistrierung einer Wärmepumpe ===&lt;br /&gt;
&lt;br /&gt;
Das nachfolgende Beispiel zeigt die besondere Möglichkeit zur Registrierung (ab V2.0.0.) einer Wärmepumpe - aber nur wenn &#039;&#039;&#039;aiConActivate=1&#039;&#039;&#039; =&amp;gt; KI-Consumerprognose &amp;lt;== gesetzt und genutzt wird! &lt;br /&gt;
&lt;br /&gt;
Hinweis : Aktuell ist &amp;quot;nur&amp;quot; die Datensammlung für den &#039;opmode&#039; aktiv - noch keine CON-Betrachtung dieser Werte bis V2.8.1 -&amp;gt; 04-.07.2026)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EM_Waermepumpe &lt;br /&gt;
aliasshort=WP&lt;br /&gt;
type=heatpump&lt;br /&gt;
etotal=Bezug_Wirkleistung_Zaehler:kWh&lt;br /&gt;
icon=sani_heating_heatpump@orange &lt;br /&gt;
mode=mustNot&lt;br /&gt;
modulation=MQTT_EMSwp:boiler_data_heatingpumpmod&lt;br /&gt;
noshow=0&lt;br /&gt;
opmode=Forecast:user_wpmodus&lt;br /&gt;
pcurr=Bezug_Wirkleistung:W:100&lt;br /&gt;
power=3183&lt;br /&gt;
switchdev=MQTT_EMSwp   ### extra wg. swstate Reading auf MQTT_EMSwp&lt;br /&gt;
swstate=boiler_data_hpactivity:heating|cooling|hot.*|pool|poolheating|defrost:off&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erläuterungen zu diesen &#039;besondern&#039; Einträgen&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;heatpump&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|Für Wärmepumpen / Klimaanlagen etc.&lt;br /&gt;
Es aktiviert sich ein Feature-Set für Wärmepumpen. Dadurch ändern sich die Strukturen und das &#039;runConTrain&#039; muß erneuert gestartet werden.&lt;br /&gt;
In dem Status des Consumer-KI-Status-Popup ist auch erkennbar ob die Wärmepumpe erkannt wird und welches Featureset verwendet wird. Es sollte aber dann z.B. beim &#039;&#039;&amp;lt;nowiki/&amp;gt;&#039;attr aiControl aiConProfile=XYX&#039;&amp;lt;nowiki/&amp;gt;&#039;&#039; das Flag &#039;&#039;&#039;heatpump&#039;&#039;&amp;lt;nowiki/&amp;gt;&#039; zusätzlich gesetzt werden.&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;etotal&#039;&#039;&#039;&lt;br /&gt;
|der Schlüssel ist Pflichtangabe &lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;mode&#039;&#039;&#039;&lt;br /&gt;
|mustNot (Empfehlung bei modulierenden Gerätetypen)&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;Bei dem Verbrauchertyp &#039;&#039;&#039;heatpump&#039;&#039;&#039; ist sicherzustellen, dass keine doppelte Regelung durch SolarForecast und die native Gerätesteuerung erfolgt. Daher sollte bei modulierenden Verbrauchern dieses Types der Eintrag meist genutzt werden.&#039;&#039; &lt;br /&gt;
&#039;&#039;Ab V2.8.1 kann auch ein &amp;quot;can&amp;quot; oder &amp;quot;must&amp;quot; - wie bei allen anderen Verbrauchertypen - zur Einplanung / Steuerung durch Solarforecast genutzt  werden.&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;modulation&#039;&#039;&#039;&lt;br /&gt;
|Modulation des Aggregates in % (Pflichtangabe). Die mögliche Syntax ist: &lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;&amp;lt;Device&amp;gt;:&amp;lt;Reading&amp;gt;&#039;&#039;&#039; - Kombination welche die aktuelle Modulation (&#039;&#039;&#039;0..100&#039;&#039;&#039;) in % liefert &lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;100&#039;&#039;&#039; - feste Modulation von 100% für nichtmodulierende Geräte &lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;opmode&#039;&#039;&#039;&lt;br /&gt;
|definiert eine &amp;lt;Device&amp;gt;:&amp;lt;Reading&amp;gt; Kombination welche den aktuellen Betriebsmodus liefert (Pflichtangabe). &lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|Syntax: &#039;&#039;&#039;&amp;lt;Device&amp;gt;:&amp;lt;Reading&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|Die Rückgabe muß genau ein Wert der folgenden Auswahl sein: &#039;&#039;&#039;off heating defrost hotwater cooling pool poolheating&#039;&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;pcurr&#039;&#039;&#039;&lt;br /&gt;
|der Schlüssel ist Pflichtangabe - Maximale Leistungsaufnahme der Wärmepumpe / Klimaanlage etc. in W.&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;power&#039;&#039;&#039;&lt;br /&gt;
|maximale Leistungsaufnahme in W. Der Wert darf nicht! 0 sein. Der Schlüssel ist Pflichtangabe. &lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;swstate&#039;&#039;&#039;&lt;br /&gt;
|Schaltstatus des Kompressors. Die Syntax bleibt wie bei den anderen Consumern. &lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|Abweichend von anderen Consumern ist die Angabe verpflichtend, auch wenn der default verwendet werden soll.&lt;br /&gt;
Durch Erstellung eines passenden userReadings (WP-komplett / WP-Heizen / WP-Kühlen / WP-WW-Aufbereitung etc.) kann damit gesteuert werden, ob man sowohl Laufzeiten für Heiz- und Kühlbetrieb, Warmwassererzeugung und Heizstabbetrieb etc. in einem Consumer zusammenfassen will, oder ob man z.B. ausschließlich nur die Laufzeiten des Heiz- und Kühlbetriebs als aktive Zeiten für die Heizung (Kühlung) in dem jeweiligen consumerXX separat erfassen möchte.&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|Alle hier nicht angezogen Parameter sind wie in allen Verbrauchern zu nutzen &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Registrierung eines Shelly Devices ===&lt;br /&gt;
&lt;br /&gt;
Nachfolgendes Beispiel zeigt eine Registrierung eines Heizlüfters der an einem Shelly Zwischenstecker angeschlossen ist und durch das Modul gesteuert werden soll. Dabei soll die Steuerung nicht nur von der Solarprognose, sondern auch von der Raumtemperatur abhängig erfolgen. Im Beispiel wird das Attribut consumer03 verwendet.&lt;br /&gt;
&lt;br /&gt;
Zwingende Angaben sind&lt;br /&gt;
&lt;br /&gt;
 consumerXX &amp;lt;Device Name&amp;gt; type=&amp;lt;type&amp;gt; power=&amp;lt;power&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Alle Angaben können mehrzeilig eingegeben werden. Die Schlüssel-Werte Paare sind jeweils durch ein Leerzeichen getrennt.&lt;br /&gt;
&lt;br /&gt;
 consumerXX Shelly.shellyplug3 type=heater power=1700 &lt;br /&gt;
&lt;br /&gt;
In dem Beispiel ist Shelly.shellyplug3 der Devicename des Shellies in FHEM. Der Schlüssel &#039;&#039;&#039;type&#039;&#039;&#039; definiert die Art des Verbrauchers. In der Hilfe sind die möglichen Typen aufgeführt. Den richtigen Typ anzugeben hat Einfluß auf die spätere Einschätzung des Leistungsverhaltens über die Laufzeit. So wird von einem &#039;&#039;&#039;heater&#039;&#039;&#039; gleich nach dem Einschalten die angegebene Nominalleistung abgerufen und wird über die Zeit gleichbleiben. &lt;br /&gt;
Eine Waschmaschine oder ein Trockner rufen über ihre Laufzeit die Leistung nicht gleichbleibend ab und ändern die Leistungsaufnahme sich über die Einschaltdauer.&lt;br /&gt;
&lt;br /&gt;
Die Angabe von &#039;&#039;&#039;power&#039;&#039;&#039; definiert die Nominalleistung (Watt) die für den Verbraucher laut Typenschild vom Hersteller angegeben wird. Diese Angabe wird vom Modul bei der Planung der Einschaltzeiten verwendet indem die Nominalleistung in das Verhältnis zur Solarprognose bzw. Verbrauchsprognose des Netzes gesetzt wird. Weiterhin ist dieser Wert auch wichtig um später den tatsächlichen Einschaltzeitpunkt auszuführen wenn ein realer PV Überschuss festgestellt wird.&lt;br /&gt;
&lt;br /&gt;
Es ist möglich &#039;&#039;&#039;power=0&#039;&#039;&#039; zu setzen. Das führt dazu, dass die Planung und letztendlich auch der Schaltvorgang unabhängig von der Solarprognose bzw. einem realen PV Überschuss vorgenommen wird.  &lt;br /&gt;
&lt;br /&gt;
Es werden weitere Schlüsseleingaben vorgenommen:&lt;br /&gt;
&lt;br /&gt;
 Shelly.shellyplug3 type=heater power=1700 icon=vent_ventilation mode=can notbefore=09 mintime=SunPath:60:-60 on=on off=off&lt;br /&gt;
&lt;br /&gt;
Mit dem Schlüssel &#039;&#039;&#039;icon&#039;&#039;&#039; legt man ein Icon fest welches in der Grafik für den Verbraucher verwendet wird. Der &#039;&#039;&#039;mode&#039;&#039;&#039; definiert die Art und Weise der Einplanung:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;can: Die Einplanung erfolgt zum Zeitpunkt mit wahrscheinlich genügend verfügbaren PV Überschuss. Der Start des Verbrauchers zum Planungszeitpunkt unterbleibt bei ungenügendem PV-Überschuss.&lt;br /&gt;
&lt;br /&gt;
;must: Der Verbaucher wird optimiert eingeplant auch wenn wahrscheinlich nicht genügend PV Überschuss vorhanden sein wird. Der Start des Verbrauchers erfolgt auch bei ungenügendem PV-Überschuss.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;&#039;notbefore&#039;&#039;&#039; wird festgelegt, dass die Einplanung nicht vor neun Uhr morgens erfolgen soll auch falls schon genügend PV Überschuss vorhanden wäre. Der Schlüssel &#039;&#039;&#039;mintime&#039;&#039;&#039; definiert die Einplanungsdauer des Verbrauchers in Minuten im einfachsten Fall. Die hier verwendete Angabe &#039;&#039;&#039;SunPath&#039;&#039;&#039; ist ein Spezialfall. Der Verbraucher soll von Sonnenaufgang bis Sonnenuntergang eingeschaltet werden, wobei die Angabe von 60 bzw. -60 ein relative Verschiebung bewirken. Dadurch wird das Einschalten 60 Mintuen nach Sonnenaufgang bis 60 Minuten vor Sonnenuntergang geplant.&lt;br /&gt;
&lt;br /&gt;
Die Schlüssel &#039;&#039;&#039;on&#039;&#039;&#039; und &#039;&#039;&#039;off&#039;&#039;&#039; teilen dem Modul die jeweiligen gültigen Ein- und Aus-Kommandos mit, mit dem das (Shelly)Device geschaltet werden kann. Werden diese Schlüssel nicht oder &amp;quot;leer&amp;quot; (on= off=) angegeben, erfolgt kein Schalten durch das Modul, nur die Planungsdaten werden erzeugt.&lt;br /&gt;
&lt;br /&gt;
Die Verbraucherregistrierung wird mit weiteren Angaben ergänzt um das gewünschte Verhalten zu erreichen:&lt;br /&gt;
&lt;br /&gt;
 Shelly.shellyplug3 type=heater power=1700 icon=vent_ventilation mode=can notbefore=09 mintime=SunPath:60:-60 on=on off=off etotal=relay_0_energy_Wh:Wh  &lt;br /&gt;
 pcurr=relay_0_power:W auto=automatic interruptable=og.bad.wandthermostat:diff-temp:[0-9]\.[0-9]:0.2&lt;br /&gt;
&lt;br /&gt;
In &#039;&#039;&#039;etotal&#039;&#039;&#039; wird der Readingname des Shelly Devices angegeben welches die Summe der verbrauchten Energie (Wh/kWh) des Consumer Device liefert. D.h. es muß ein sich stetig erhöhender Wert sein. Durch die Auswertung dieses Readings ermittelt das Modul die in bestimmten Zeiteinheiten verbrauchte Energie zur weiteren Verwendung. &lt;br /&gt;
&lt;br /&gt;
In dem Shelly Device ist per default ein solches Reading nicht vorhanden. Über userReadings kann in dem Device Shelly.shellyplug3 ein Reading für etotal erzeugt werden:&lt;br /&gt;
&lt;br /&gt;
 userReadings relay_0_energy_Wh:relay_0_energy.* monotonic { sprintf &amp;quot;%.0f&amp;quot;, ReadingsVal ($name, &#039;relay_0_energy&#039;, 0) / 60 } &lt;br /&gt;
&lt;br /&gt;
Der Schlüssel &#039;&#039;&#039;pcurr&#039;&#039;&#039; enthält das Reading in Shelly.shellyplug3 welches den aktuellen Energieverbrauch liefert. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;auto&#039;&#039;&#039; enthält das Reading in Shelly.shellyplug3 welches zur Freigabe/Sperrung der autmatischen Schaltung durch das Modul dienen soll. Ist das angegebene Reading (im Beispiel &amp;quot;automatic&amp;quot;) im Shelly.shellyplug3 nicht vorhanden, wird es vom Modul automatisch mit dem Wert &amp;quot;1&amp;quot; angelegt.&lt;br /&gt;
Dadurch ist per default das automatische Schalten von Shelly.shellyplug3 durch das Modul freigegeben. &lt;br /&gt;
Der User kann durch Setzen des Readings &#039;&#039;&#039;automatic=0&#039;&#039;&#039; das automatische Schalten durch das Modul sperren und mit &amp;quot;1&amp;quot; wieder freigeben. Dadurch kann man zu bestimmten Zeiten (Urlaub, Feiertage, etc.) die Schaltung temporär deaktivieren.&lt;br /&gt;
&lt;br /&gt;
Wie oben beschrieben, soll der Heizlüfter als weitere Schaltbedingung die Abhängigkeit von der Raumtemperatur beachten. Konkret soll der Heizlüfter mit einer Hysterese von 0.2 (Grad) bei Erreichen einer Soll-Raumtemperatur ausschalten und bei Unterschreiten einer bestimmten Temperatur einschalten.&lt;br /&gt;
Der Schlüssel &#039;&#039;&#039;interruptable&#039;&#039;&#039; übernimmt diese temporäre Schaltsequenzen.&lt;br /&gt;
&lt;br /&gt;
Zunächst wird in dem Sensordevice (In dem Beispiel ein Homatic Wandthermostat HM-TC-IT-WM-W-EU) ein Reading erstellt welches dann im Schlüssel &#039;&#039;&#039;interruptable&#039;&#039;&#039; angegeben wird. Dieses Reading soll einen Wert enthalten auf den der angegebene Regex ([0-9]\.[0-9]) matchen soll um Shelly.shellyplug3 temporär auszuschalten.&lt;br /&gt;
Im Wandthermostat wird dazu ein userReading angelegt:&lt;br /&gt;
&lt;br /&gt;
 userReadings diff-temp:desired-temp.* { &lt;br /&gt;
     sprintf &amp;quot;%.1f&amp;quot;, ReadingsVal ($name, &#039;measured-temp&#039;, 0) - ReadingsVal ($name, &#039;desired-temp&#039;, 0) &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das bedeutet, wenn die Raumtemperatur die Solltemperatur erreicht oder höher ist, wird diff-temp &amp;gt;= 0.&lt;br /&gt;
In diesem Fall matcht der angebene Regex in:&lt;br /&gt;
&lt;br /&gt;
 interruptable=og.bad.wandthermostat:diff-temp:&#039;&#039;&#039;[0-9]\.[0-9]&#039;&#039;&#039;:0.2&lt;br /&gt;
&lt;br /&gt;
und Shelly.shellyplug3 wird ausgeschaltet. &lt;br /&gt;
Unterschreitet der Wert von diff-temp 0, matcht der Regex nicht mehr und der Verbraucher wird wieder eingeschaltet. Dabei wird die angegebene Hysterese berücksichtigt, d.h der Verbraucher wird erst ausgeschaltet wenn &amp;quot;diff-temp - 0.2 &amp;gt;= 0&amp;quot; wahr ist.&lt;br /&gt;
&lt;br /&gt;
Für das Wiedereinschalten des Heizlüfters ist außerdem Voraussetzung, dass ein entsprechender PV-Überschuss vorliegt. Diese Bedingung wird durch die Angabe von &#039;&#039;&#039;power=1700&#039;&#039;&#039; bewirkt. Soll der zwangsweise PV Überschuss ignoriert werden, kann &#039;&#039;&#039;power=0&#039;&#039;&#039; angegeben werden. Alternativ kann die Berücksichtigung des zwangsweisen PV Überschuss mit dem Schlüssel &amp;quot;spignorecond&amp;quot; im Consumer-Attribut ausgesteuert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== zusätzliche Readings bzw. Erzeugung von statistischen Readings ==&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zu den zahlreichen im Modul per Standard erzeugten Readings kann der Anwender weitere Readings generieren lassen.&lt;br /&gt;
Diese zusätzlichen Readings geben entweder einen bestimmten Sachverhalt (Laufzeit, Status der API-Abfragen, etc.) oder einen statistischen Wert, z.B. die Batterieentladung des aktuellen Tages, wieder.&lt;br /&gt;
&lt;br /&gt;
Die zusätzlich erstellten Readings sind durch den Präfix &#039;&#039;&#039;special_&#039;&#039;&#039; im Device gekennzeichnet.&lt;br /&gt;
&lt;br /&gt;
Diese zusätzlichen Informationen können durch das Setzen einer oder mehrerer Kennzeichen im Attribut &#039;&#039;&#039;ctrlSpecialReadings&#039;&#039;&#039; erzeugt werden. Die mögliche Auswahl wird je nach Bedarf ausgebaut und umfasst zum aktuellen Zeitpunkt (07.02.2025) diese Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;BatPowerIn_Sum: 	die Summe der momentanen Batterieladeleistung aller definierten Batterie Geräte&lt;br /&gt;
;BatPowerOut_Sum: 	die Summe der momentanen Batterieentladeleistung aller definierten Batterie Geräte&lt;br /&gt;
;allStringsFullfilled: 	Erfüllungsstatus der fehlerfreien Generierung aller Strings&lt;br /&gt;
;conForecastTillNextSunrise: 	Verbrauchsprognose von aktueller Stunde bis zum kommenden Sonnenaufgang&lt;br /&gt;
;currentAPIinterval: 	das aktuelle Abrufintervall der gewählten Strahlungsdaten-API in Sekunden&lt;br /&gt;
;currentRunMtsConsumer_XX: 	die Laufzeit (Minuten) des Verbrauchers &amp;quot;XX&amp;quot; seit dem letzten Einschalten. (letzter Laufzyklus)&lt;br /&gt;
;dayAfterTomorrowPVforecast: 	liefert die Vorhersage der PV Erzeugung für Übermorgen (sofern verfügbar) ohne Autokorrektur (Rohdaten).&lt;br /&gt;
;daysUntilBatteryCare_XX: 	Tage bis zur nächsten Batterie XX Pflege (Erreichen der Ladung &#039;maxSoC&#039; aus Attribut ctrlBatSocManagementXX)&lt;br /&gt;
;lastretrieval_time: 	der letzte Abrufzeitpunkt der gewählten Strahlungsdaten-API&lt;br /&gt;
;lastretrieval_timestamp: 	der Timestamp der letzen Abrufzeitpunkt der gewählten Strahlungsdaten-API&lt;br /&gt;
;response_message: 	die letzte Statusmeldung der gewählten Strahlungsdaten-API&lt;br /&gt;
;runTimeAvgDayConsumer_XX: 	die durchschnittliche Laufzeit (Minuten) des Verbrauchers &amp;quot;XX&amp;quot; an einem Tag&lt;br /&gt;
;runTimeCentralTask: 	die Laufzeit des letzten SolarForecast Intervalls (Gesamtprozess) in Sekunden&lt;br /&gt;
;runTimeTrainAI: 	die Laufzeit des letzten KI Trainingszyklus in Sekunden&lt;br /&gt;
;runTimeLastAPIAnswer: 	die letzte Antwortzeit des Strahlungsdaten-API Abrufs auf einen Request in Sekunden&lt;br /&gt;
;runTimeLastAPIProc: 	die letzte Prozesszeit zur Verarbeitung der empfangenen Strahlungsdaten-API Daten&lt;br /&gt;
;SunMinutes_Remain: 	die verbleibenden Minuten bis Sonnenuntergang des aktuellen Tages&lt;br /&gt;
;SunHours_Remain: 	die verbleibenden Stunden bis Sonnenuntergang des aktuellen Tages&lt;br /&gt;
;todayConsumptionForecast: 	Verbrauchsprognose pro Stunde des aktuellen Tages (01-24)&lt;br /&gt;
;todayConForecastTillSunset: 	Verbrauchsprognose von aktueller Stunde bis Stunde vor Sonnenuntergang&lt;br /&gt;
;todayDoneAPIcalls: 	die Anzahl der am aktuellen Tag ausgeführten Strahlungsdaten-API Calls&lt;br /&gt;
;todayDoneAPIrequests: 	die Anzahl der am aktuellen Tag ausgeführten Strahlungsdaten-API Requests&lt;br /&gt;
;todayConsumption: 	der gesamte Energieverbrauch (Wh) des Hauses am aktuellen Tag&lt;br /&gt;
;todayGridConsumption: 	die aus dem öffentlichen Netz bezogene Energie am aktuellen Tag&lt;br /&gt;
;todayGridFeedIn: 	die in das öffentliche Netz eingespeiste PV Energie am aktuellen Tag&lt;br /&gt;
;todayMaxAPIcalls: 	die maximal mögliche Anzahl Strahlungsdaten-API Calls. Ein Call kann mehrere API Requests enthalten.&lt;br /&gt;
;todayRemainingAPIcalls: 	die Anzahl der am aktuellen Tag noch möglichen Strahlungsdaten-API Calls&lt;br /&gt;
;todayRemainingAPIrequests: 	die Anzahl der am aktuellen Tag noch möglichen Strahlungsdaten-API Requests&lt;br /&gt;
;todayBatIn_XX: 	die am aktuellen Tag in die Batterie XX geladene Energie&lt;br /&gt;
;todayBatInSum: 	Summe der am aktuellen Tag in alle Batterien geladene Energie&lt;br /&gt;
;todayBatOut_XX: 	die am aktuellen Tag aus der Batterie XX entnommene Energie&lt;br /&gt;
;todayBatOutSum: 	Summe der am aktuellen Tag aus allen Batterien entnommene Energie&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig:&#039;&#039;&#039; Manche Angaben sind im Setup des Moduls optional, d.h. sie müssen nicht zwingend beim Setup angegeben werden. Allerdings sind diese Angaben für die Erstellung eines zusätzlichen Readings unter Umständen Voraussetzung. Es empfiehlt sich deshalb bei Setup so viele Informationen wie möglich zu übermitteln.&lt;br /&gt;
&lt;br /&gt;
So ist zum Beispiel für die sinnvolle Erstellung der Informationen &#039;&#039;&#039;todayBatInSum&#039;&#039;&#039; und &#039;&#039;&#039;todayBatOutSum&#039;&#039;&#039; (Readings special_todayBatInSum und special_todayBatOutSum) das Vorhandensein der Schlüssel &#039;&#039;intotal&#039;&#039; und &#039;&#039;outtotal&#039;&#039; im Attribut setupBatteryDevXX notwendig (Beispiel):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr &amp;lt;Name&amp;gt; setupBatteryDev01 MQTT2_cerboGX_c0619ab34e08_battery &lt;br /&gt;
                              pin=BatIn:W pout=BatOut:W charge=SOC_value intotal=BatInTotal:Wh outtotal=BatOutTotal:Wh &lt;br /&gt;
                              cap=InstalledCapacity_Wh:Wh asynchron=1 show=1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hinweise zur Fehlersuche ==&lt;br /&gt;
Das Modul SolarForecast ist sehr komplex und es die verschiedensten Datenquellen ausgewertet, zusammengeführt und daraus Ergebnisse berechnet und/oder visualisiert. Wird etwas nicht wie erwartet durch das Modul geliefert, können die Ursachen vielfältig sein. Natürlich kann ein Fehler im Modulcode vorliegen, oftmals gibt es aber andere Ursachen.&lt;br /&gt;
&lt;br /&gt;
Die nachfolgenden Hinweise sollen Hilfe zur Selbsthilfe geben und sind eine Zusammenfassung von realen Fällen die mit dem beschriebenen Wegen und Verfahren gelöst wurden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Die erwartete erzeugte PV-Energie ist im Modul zu gering und wird im Balkendiagramm nicht angezeigt === &lt;br /&gt;
&lt;br /&gt;
Die erzeugte PV-Energie wird nicht richtig angezeigt: Am Vormittag sind keine Werte vorhanden und, wenn dann etwas kommt, ist die Anzeige zu gering. Für 13 und 14 Uhr wurden ca. 5.000Wh erwartet (im Vergleich mit den Daten aus einer anderen Auswertungsquelle). &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lösungsweg:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Aus dem List des Devices wurden die für den Fall wesentlichen Readings herausgezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    2025-02-02 08:59:55  Today_Hour09_PVforecast 152 Wh&lt;br /&gt;
    2025-02-02 08:59:55  Today_Hour09_PVreal 0 Wh&lt;br /&gt;
&lt;br /&gt;
    2025-02-02 09:59:55  Today_Hour10_PVforecast 1400 Wh&lt;br /&gt;
    2025-02-02 09:59:55  Today_Hour10_PVreal 0 Wh&lt;br /&gt;
&lt;br /&gt;
    2025-02-02 10:59:55  Today_Hour11_PVforecast 2500 Wh&lt;br /&gt;
    2025-02-02 10:59:55  Today_Hour11_PVreal 0 Wh&lt;br /&gt;
&lt;br /&gt;
    2025-02-02 11:59:55  Today_Hour12_PVforecast 4392 Wh&lt;br /&gt;
    2025-02-02 11:59:55  Today_Hour12_PVreal 0 Wh&lt;br /&gt;
&lt;br /&gt;
    2025-02-02 12:59:54  Today_Hour13_PVforecast 4000 Wh&lt;br /&gt;
    2025-02-02 12:59:54  Today_Hour13_PVreal 300 Wh&lt;br /&gt;
&lt;br /&gt;
    2025-02-02 13:59:54  Today_Hour14_PVforecast 6415 Wh&lt;br /&gt;
    2025-02-02 13:59:54  Today_Hour14_PVreal 3200 Wh&lt;br /&gt;
&lt;br /&gt;
    2025-02-02 14:59:54  Today_Hour15_PVforecast 5629 Wh&lt;br /&gt;
    2025-02-02 14:59:54  Today_Hour15_PVreal 2700 Wh&lt;br /&gt;
&lt;br /&gt;
    2025-02-02 15:59:54  Today_Hour16_PVforecast 3958 Wh&lt;br /&gt;
    2025-02-02 15:59:54  Today_Hour16_PVreal 900 Wh&lt;br /&gt;
&lt;br /&gt;
    2025-02-02 16:31:24  Today_Hour17_PVforecast 945 Wh&lt;br /&gt;
    2025-02-02 16:31:24  Today_Hour17_PVreal 500 Wh&lt;br /&gt;
   &lt;br /&gt;
    2025-02-02 16:31:24  Today_Hour18_PVforecast 59 Wh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man sieht dass bis 12:00 keine erzeugte Energie vom WR gemeldet wird. Deswegen wird in der Balkengrafik nichts dargestellt. Auch danach bleibt die registrierte PV-Energie hinter den Erwartungen zurück. Zuständig für die Lieferung der PV-Energie an das Modul ist das Reading im Schlüssel:&lt;br /&gt;
&lt;br /&gt;
 setupInverterDev01 SH10rt pv=Total_DC_Power:W &amp;lt;mark&amp;gt;etotal=Total_Export_Energy_from_PV:kWh&amp;lt;/mark&amp;gt; capacity=10000 strings=Hauptdach,Flachdach&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Welche Änderungen es zwischen den Stunden gab, sieht man mit einem &amp;quot;get ... pvHistory XX&amp;quot; (&amp;quot;XX&amp;quot; steht für das Datum, d.h. den Tag, z.B. 02). &amp;lt;br&amp;gt;&lt;br /&gt;
Hier ein Beispiel für die Stunden 10 (9:00 - 9:59) und 11 (10:00 - 10:59). &amp;lt;br&amp;gt;&lt;br /&gt;
Wichtig ist hier der Key etotali01 für den ersten Inverter. Die Differenz zwischen den Werten beider Stunden ist die in der Stunde erzeugte Energie (hier 380 Wh). Diese 380 Wh findest du auch im Key pvrl01 als PVReal für diese Stunde. Das Modul rechnet intern immer mit Wh, kWh werden vorher in Wh umgerechnet.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
10 =&amp;gt; pvfc: 365, pvrl: 530, pvrlvd: 1, rad1h: -&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;mark&amp;gt;etotali01: 63364714&amp;lt;/mark&amp;gt;, etotali02: 3044110, etotali03: -&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;mark&amp;gt;pvrl01: 380&amp;lt;/mark&amp;gt;, pvrl02: 150, pvrl03: -&lt;br /&gt;
&lt;br /&gt;
            etotalp01: -, etotalp02: -, etotalp03: -&lt;br /&gt;
&lt;br /&gt;
            pprl01: -, pprl02: -, pprl03: -&lt;br /&gt;
&lt;br /&gt;
            confc: 574, con: 518, gcons: 22, conprice: 0.2958&lt;br /&gt;
&lt;br /&gt;
            gfeedin: 1, feedprice: 0.1269&lt;br /&gt;
&lt;br /&gt;
            DoN: 1, sunaz: 137, sunalt: 12&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
&lt;br /&gt;
            &lt;br /&gt;
&lt;br /&gt;
      11 =&amp;gt; pvfc: 2966, pvrl: 1862, pvrlvd: 1, rad1h: -&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;mark&amp;gt;etotali01: 63365094&amp;lt;/mark&amp;gt;, etotali02: 3044260, etotali03: -&lt;br /&gt;
&lt;br /&gt;
            pvrl01: 1392, pvrl02: 470, pvrl03: -&lt;br /&gt;
&lt;br /&gt;
            etotalp01: -, etotalp02: -, etotalp03: -&lt;br /&gt;
&lt;br /&gt;
            pprl01: -, pprl02: -, pprl03: -&lt;br /&gt;
&lt;br /&gt;
            confc: 774, con: 609, gcons: 25, conprice: 0.2958&lt;br /&gt;
&lt;br /&gt;
            gfeedin: 4, feedprice: 0.1269&lt;br /&gt;
           &lt;br /&gt;
....&lt;br /&gt;
&lt;br /&gt;
D.h. wenn zwischen den beiden Stunden keine Differenzen zu finden sind, liegt es sehr wahrscheinlich am Input des Readings:&lt;br /&gt;
&lt;br /&gt;
 etotal=Total_Export_Energy_from_PV:kWh&lt;br /&gt;
&lt;br /&gt;
welches sich in den ersten Stunden nicht ändert und danach auch nur wenig.&lt;br /&gt;
&lt;br /&gt;
Man kann mit dem Attribut:&lt;br /&gt;
&lt;br /&gt;
 ctrlDebug=collectData&lt;br /&gt;
&lt;br /&gt;
die Datensammlung verfolgen (leider entstehen viele Daten im Log). Man sieht welche Werte von dem Inverter/Reading geliefert werden:&lt;br /&gt;
 &lt;br /&gt;
 ....&lt;br /&gt;
 2025.02.02 19:10:10.558 1: SolCast DEBUG&amp;gt; collect Inverter 01 data - device: STP_5000, delivery: default =&amp;gt;&lt;br /&gt;
 2025.02.02 19:10:10.558 1: SolCast DEBUG&amp;gt; pv: 0 W, &amp;lt;mark&amp;gt;etotal: 63378810 Wh&amp;lt;/mark&amp;gt;&lt;br /&gt;
 ....&lt;br /&gt;
&lt;br /&gt;
Dieser Wert muß bei PV Erzeugung kontinuierlich hochzählen. Wenn nicht, muss das angegebene Reading, d.h. die Quelle überprüft werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ergebnis der Prüfung:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Tatsächlich wurde ein Reading benutzt, das ungeeignet war: Statt &amp;quot;Total_PV_Generation&amp;quot; wurde &amp;quot;Total_export_energy_from_PV&amp;quot; genutzt. In diesem Reading wurde immer die in die Batterie gespeicherte Energie von der gesamten erzeugten Energie abgezogen. Daher war auch vormittags alles 0, da in dieser Periode alle PV-Energie in die Batterie geladen wurde bzw. in weiteren Stunden ein Anteil der dann bei dem PV-Erzeugungswert fehlte.&lt;br /&gt;
&lt;br /&gt;
Nachdem die Ursache beseitigt war, zeigt SolarForecast wieder die erwarteten PV-Erzeugungswerte an.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Ich beobachte Blockierungen in meinem FHEM - ist SolarForecast eventuell der Verursacher? === &lt;br /&gt;
&lt;br /&gt;
==== Übersicht ====&lt;br /&gt;
&lt;br /&gt;
Dieses Dokument beschreibt die systematische Vorgehensweise zur Analyse und Lokalisierung von Blockierungszuständen im Kontext von SolarForecast (SF). Es dient als allgemeine Handlungsanleitung, um Ursachen für Systemverzögerungen oder hängende Prozesse einzugrenzen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Grundprinzipien der SF-Architektur ==== &lt;br /&gt;
&lt;br /&gt;
Bevor mit der Analyse begonnen wird, sind folgende Architekturmerkmale von SF zu verstehen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Alle API-Abfragen sind non-blocking&#039;&#039;&#039; ausgeführt. SF selbst blockiert den FHEM-Interpreter durch API-Kommunikation grundsätzlich nicht.&lt;br /&gt;
* &#039;&#039;&#039;Geräteabfragen und Datensammlungen&#039;&#039;&#039; erfolgen ausschließlich durch das Auslesen von Readings – &#039;&#039;&#039;nicht&#039;&#039;&#039; durch direkte Geräteabfragen. Die direkte Gerätekommunikation ist Aufgabe der jeweiligen Gerätemodule.&lt;br /&gt;
* &#039;&#039;&#039;Schaltvorgänge von Verbrauchern&#039;&#039;&#039; (Consumer) können potenziell Blockierungen verursachen, wenn das zugehörige Gerätemodul beim Schalten auf ein Schaltergebnis wartet (blockierender Aufruf im Gerätemodul).&lt;br /&gt;
* &#039;&#039;&#039;SF schreibt in regelmäßigen Abständen&#039;&#039;&#039; modulinterne Datenstrukturen in das Filesystem. Ein fehlerhaftes oder langsames Filesystem kann daher eine Blockierungsquelle darstellen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schritt-für-Schritt-Analyse ==== &lt;br /&gt;
&lt;br /&gt;
===== Schritt 1: Meldungen im Log identifizieren und zuordnen ===== &lt;br /&gt;
&lt;br /&gt;
Beim Auftreten von Auffälligkeiten zunächst das FHEM-Log auf bekannte Meldungen prüfen und deren Herkunft bestimmen.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Beispielmeldung !! Herkunft !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Data cycle triggered, watch readings&amp;lt;/code&amp;gt; || Rückmeldung der SF-Zentralschleife (von get &amp;lt;SF-Device&amp;gt; data) || Normaler Abschluss eines SF-Zyklus – zu diesem Zeitpunkt ist die Verarbeitung vollständig abgeschlossen. Kein Hinweis auf eine SF-interne Blockierung.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SolCast DEBUG&amp;gt; AI FANN drift data type &#039;con&#039; successfully written to file: ./FHEM/FhemUtils/NeuralNet_SolarForecast_SolCast&amp;lt;/code&amp;gt; || Eine Log-Ausgabe mit aktiviertem Debug || Logausgaben von SF erfolgen IMMER mit Angabe des SF-Namens (hier &#039;SolCast&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;There are still path commands in the action queue&amp;lt;/code&amp;gt; || Nicht von SF stammende Rückmeldung || Hinweis auf eine Warteschlange in einem Gerätemodul. Ursache im jeweiligen Gerätemodul suchen, nicht in SF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Meldungen, die nicht von SF generiert werden, müssen beim Hersteller bzw. Maintainer des jeweiligen Gerätemoduls analysiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Schritt 2: Laufzeit der SF-Zentralschleife messen ===== &lt;br /&gt;
&lt;br /&gt;
Um zu beurteilen, ob SF selbst verzögert läuft, das Special Reading &amp;lt;code&amp;gt;runTimeCentralTask&amp;lt;/code&amp;gt; aktivieren:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;SF-Device&amp;gt; ctrlSpecialReadings runTimeCentralTask&lt;br /&gt;
&lt;br /&gt;
Dieses Reading liefert die &#039;&#039;&#039;Gesamtlaufzeit eines SF-Schleifenzyklus&#039;&#039;&#039; inklusive aller enthaltenen Abfragen und Verarbeitungsschritte.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Typische Werte:&#039;&#039;&#039; 0,2 – 0,3 Sekunden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Schritt 3: Laufzeiten loggen und auswerten ===== &lt;br /&gt;
&lt;br /&gt;
Die Werte des Readings &amp;lt;code&amp;gt;special_runTimeCentralTask&amp;lt;/code&amp;gt; dauerhaft mitschreiben, um Ausreißer und zeitliche Muster zu erkennen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Logging:&#039;&#039;&#039; via FileLog oder DbLog&lt;br /&gt;
* &#039;&#039;&#039;Auswertung:&#039;&#039;&#039; via SVG-Plot oder DbRep&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Durch die zeitliche Auswertung lässt sich erkennen:&lt;br /&gt;
* &#039;&#039;&#039;ob&#039;&#039;&#039; Blockierungen auftreten&lt;br /&gt;
* &#039;&#039;&#039;wann&#039;&#039;&#039; sie auftreten (Uhrzeit, Regelmäßigkeit)&lt;br /&gt;
* &#039;&#039;&#039;im Zusammenhang womit&#039;&#039;&#039; sie auftreten (z. B. Consumer-Schaltvorgänge)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Schritt 4: Consumer-Schaltvorgänge als Ursache prüfen ===== &lt;br /&gt;
&lt;br /&gt;
Falls Verbraucher (Consumer) aktiv geschaltet werden, ist dies eine &#039;&#039;&#039;priorisierte Spur&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
* Identifizieren, welche Gerätemodule beim Schalten eines Consumers involviert sind.&lt;br /&gt;
* Prüfen, ob diese Module &#039;&#039;&#039;blockierend&#039;&#039;&#039; auf ein Schaltergebnis warten.&lt;br /&gt;
* Zeitliche Korrelation zwischen Schaltvorgängen und erhöhten &amp;lt;code&amp;gt;runTimeCentralTask&amp;lt;/code&amp;gt;-Werten im Log prüfen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Schritt 5: Filesystem prüfen ===== &lt;br /&gt;
&lt;br /&gt;
Falls keine Consumer-Schaltvorgänge als Ursache infrage kommen oder die Blockierungen unregelmäßig und zeitlich nicht korreliert auftreten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Filesystem-Gesundheit&#039;&#039;&#039; des Systems prüfen (z. B. SD-Karte bei Raspberry Pi, NFS-Mounts, volle Partitionen).&lt;br /&gt;
* SF schreibt regelmäßig Datenstrukturen auf das Filesystem. Latenzen oder Fehler dabei können SF-Zyklen verzögern.&lt;br /&gt;
* Systemlogs (&amp;lt;code&amp;gt;dmesg&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;syslog&amp;lt;/code&amp;gt;) auf I/O-Fehler oder -Warnungen prüfen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Zusammenfassung: Checkliste ==== &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! # !! Prüfpunkt !! Tool / Methode&lt;br /&gt;
|-&lt;br /&gt;
| 1 || Log-Meldungen SF-intern oder fremd? || FHEM Logfile&lt;br /&gt;
|-&lt;br /&gt;
| 2 || &amp;lt;code&amp;gt;runTimeCentralTask&amp;lt;/code&amp;gt; aktivieren || &amp;lt;code&amp;gt;ctrlSpecialReadings&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 3 || Laufzeiten loggen || FileLog / DbLog&lt;br /&gt;
|-&lt;br /&gt;
| 4 || Ausreißer zeitlich auswerten || SVG / DbRep&lt;br /&gt;
|-&lt;br /&gt;
| 5 || Korrelation mit Consumer-Schaltvorgängen? || Zeitvergleich im Log&lt;br /&gt;
|-&lt;br /&gt;
| 6 || Gerätemodul des Consumers auf blockierende Aufrufe prüfen || Modul-Doku / Maintainer&lt;br /&gt;
|-&lt;br /&gt;
| 7 || Filesystem auf Fehler / Latenz prüfen || &amp;lt;code&amp;gt;dmesg&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;df&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;iostat&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Hinweise ==== &lt;br /&gt;
&lt;br /&gt;
* SF ist &#039;&#039;&#039;nicht&#039;&#039;&#039; der unmittelbare Verursacher, wenn Fremdmodule blockierende Aufrufe ausführen.&lt;br /&gt;
* Die Analyse sollte immer mit dem &#039;&#039;&#039;Logging der Laufzeiten&#039;&#039;&#039; beginnen, da nur so eine fundierte Aussage über Zeitpunkt und Häufigkeit möglich ist.&lt;br /&gt;
* Bei Meldungen unbekannter Herkunft stets das verantwortliche Gerätemodul identifizieren, bevor SF-interne Ursachen untersucht werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Konfigurationsbeispiele ==&lt;br /&gt;
&lt;br /&gt;
=== Visualisierung solare Vorhersage und reale Erzeugung ===&lt;br /&gt;
&lt;br /&gt;
Zu Beginn jedes neuen Tages gegen 00:00 Uhr werden durch das SolarForecast Device Events für die initiale PV Prognose des kommenden Tages erstellt.&lt;br /&gt;
Der Readingteil dieser Events heißt&lt;br /&gt;
&lt;br /&gt;
 AllPVforecastsToEvent&lt;br /&gt;
&lt;br /&gt;
Die Uhrzeiten der Events sind so aufbereitet und können direkt geloggt werden um sie in einen SVG Plot zu integrieren.&lt;br /&gt;
Im SolarForecast Device ist dieses Reading nicht sichtbar, nur die Events werden erstellt.&lt;br /&gt;
&lt;br /&gt;
Die meteorologischen Bedingungen verändern sich über den Tag permanent. Je nach gewählter Strahlungsdatenquelle (eine API oder DWD Device) erfolgt eine mehr oder weniger dynamische Anpassung der Prognose an die sich verändernde Umwelt.&lt;br /&gt;
&lt;br /&gt;
Aktuelle Prognosedaten sowie die reale PV Erzeugung der vergangenen Stunde können über die Readings&lt;br /&gt;
&lt;br /&gt;
 LastHourPVforecast&lt;br /&gt;
 LastHourPVreal&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2024-10-20 134050.png|right|thumb|400px|Übersicht solare Vorhersage]]&lt;br /&gt;
geloggt werden. &lt;br /&gt;
&lt;br /&gt;
Werden alle drei Werte in einem SVG kombiniert, kann die Entwicklung der Prognose über den Tag und die Beziehung von Prognose zu realer PV Erzeugnung pro Stunde visualisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für das rechts abgebildete Beispiel des Plots aus einer Datenbank &amp;quot;LogDBShort&amp;quot; sieht das gplot-File wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2024-03-08 15:05:31&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;&amp;lt;TL&amp;gt;&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Wh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;Wh&amp;quot;&lt;br /&gt;
set yrange [0:7500]&lt;br /&gt;
set y2range [0:7500]&lt;br /&gt;
&lt;br /&gt;
#LogDBShort SolCast:LastHourPVforecast:::&lt;br /&gt;
#LogDBShort SolCast:LastHourPVreal:::&lt;br /&gt;
#LogDBShort SolCast:AllPVforecastsToEvent:::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;aktuelle PV Vorhersage&#039; ls l6fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;reale PV Erzeugung&#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;initiale PV Vorhersage&#039; ls l4 lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; In manchen Fällen werden die Vorhersagewerte im SVG-Plot nicht angezeigt wenn FileLog verwendet wird. Ein Setzen des Attribute &amp;quot;fixedrange=3days +1&amp;quot; im SVG löst das Problem. Die Definition des SVG-Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define SVG_LogDBShort_SolCast SVG LogDBShort:SVG_LogDBShort_SolCast:HISTORY&lt;br /&gt;
attr SVG_LogDBShort_SolCast fixedrange 3days +1&lt;br /&gt;
attr SVG_LogDBShort_SolCast room Energie-&amp;gt;SolarPrognose&lt;br /&gt;
attr SVG_LogDBShort_SolCast sortby 2&lt;br /&gt;
attr SVG_LogDBShort_SolCast title &amp;quot;Übersicht solare Vorhersage&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Technisch bedingt werden an einem Tag X kurz nach 00:00 Uhr die am Vortag für den Tag X erzeugten Events aktualisiert. Diese Daten erzeugen in der Datenbank einen zweiten Satz an Daten mit dem gleichen Timestamp was für die Anzeige unvorteilhaft ist. &lt;br /&gt;
Um nur die aktualisierten Events von &#039;&#039;&#039;AllPVforecastsToEvent&#039;&#039;&#039; in der Datenbank zu erhalten, bietet sich ein DbRep-Device an. Die nachfolgende Vorschlagsdefinition kann per at-Device jeden Tag kurz vor Mitternacht (z.B. 23:57:10) ausgeführt werden. Es werden immer die in der Vergangenheit geschriebenen (veralteten) Daten aus der Datenbank gelöscht, doppelte Datesätze vermieden und immer die aktuellste initiale Prognose gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define Rep.Del.AllPVforecastsToEvent DbRep LogDBShort&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent alias Löschen Readings AllPVforecastsToEvent des Folgetages&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent comment ermöglicht dass die Readings AllPVforecastsToEvent am Folgetag wieder neu und aktuell geschrieben werden können&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent devStateIcon initialized:control_3dot_hor_s connected:10px-kreis-gelb .*disconnect:10px-kreis-rot .*done:10px-kreis-gruen&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent disable 0&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent event-on-update-reading state&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent icon edit_delete&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent room Datenbank-&amp;gt;Produktiv&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent showproctime 1&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent device TYPE=SolarForecast&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent timestamp_begin next_day_begin&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent timestamp_end current_month_end&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent verbose 2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das angegebene DbLog-Device &#039;&#039;&#039;LogDBShort&#039;&#039;&#039; ist natürlich anzupassen.&lt;br /&gt;
&lt;br /&gt;
Das at-Device zum Starten der Datenbankbereinigung sieht folgendermaßen aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define At.Del.AllPVforecastsToEvent at *23:58:10 set Rep.Del.AllPVforecastsToEvent delEntries&lt;br /&gt;
attr At.Del.AllPVforecastsToEvent alias Start Löschen Readings AllPVforecastsToEventn LogDBShort&lt;br /&gt;
attr At.Del.AllPVforecastsToEvent icon clock&lt;br /&gt;
attr At.Del.AllPVforecastsToEvent room Datenbank-&amp;gt;Produktiv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Natürlich sind auch hier die eigenen Devicenamen entsprechend anzupassen.&lt;br /&gt;
&lt;br /&gt;
Ab SolarForecast Version 1.51.7 kann die Eventerzeugung für bestimmte SVG Plot-Typen optimiert werden. &amp;lt;br&amp;gt; &lt;br /&gt;
Die Aktivierung dieser Optimierungen ist in der Online Hilfe zum Attribut &#039;&#039;&#039;plantControl-&amp;gt;genPVforecastsToEvent&#039;&#039;&#039; beschrieben. Bei Nutzung des Attributes plantControl-&amp;gt;genPVforecastsToEvent ist ebenfalls das Attribut &#039;&#039;&#039;event-on-update-reading=AllPVforecastsToEvent&#039;&#039;&#039; zu setzen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispielkonfiguration 1 ===&lt;br /&gt;
Dies ist eine Konfiguration mit &lt;br /&gt;
&lt;br /&gt;
SummenDummy für 2 BatterieWR (Namen : SBS25 / SBS25_2)&lt;br /&gt;
&lt;br /&gt;
SummenDummy für 3 PV-Wechselrichter (Namen : SB25 / SB30 / SB40)&lt;br /&gt;
&lt;br /&gt;
            mit verschiedenen InverterStrings / ModulDirection / ModulTiltAngle, ModulPeakString&lt;br /&gt;
&lt;br /&gt;
und auch mit den notwendigen zugehörigen anderen Modul-Konfigs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ACHTUNG:&#039;&#039;&#039; Zusätzlich enthalten ist bei dem Beispiel-Notify eine Sonderkonstellation für eine Brennstoffzelle &amp;quot;FCU&amp;quot; als weitere bzw. zusätzliche Stromerzeugungsquelle. Diese &amp;quot;FCU&amp;quot; wird dadurch mit in der Grafik mit deren Erzeugungsleistung Tag und Nacht in der Erzeugersumme (am Symbol = Sonne) berücksichtigt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;(ReadingsVal(&amp;quot;FCU&amp;quot;,&amp;quot;FCU-Strom-aktuelle-Leistung&amp;quot;,0)/1000)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== DWD ====&lt;br /&gt;
Bitte dabei diese DWD-Version aus dem [https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter Contrib] von DS_Starter dazu nutzen&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|55_DWD_OpenData.pm&lt;br /&gt;
|136.2 KB ​&lt;br /&gt;
|29260  &lt;br /&gt;
|DS_Starter&lt;br /&gt;
|55_DWD_OpenData: contrib 1.17.7&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
define DWD DWD_OpenData&lt;br /&gt;
attr DWD downloadTimeout 120&lt;br /&gt;
attr DWD comment Im DWD Wetterdevice verwendet Solarforecast : \&lt;br /&gt;
TTT,Neff,RR1c,ww,SunUp,SunRise,SunSet \&lt;br /&gt;
zusätzlich ist jedoch auch noch Rad1h notwendig \&lt;br /&gt;
wenn dieses DWD-Device als Strahlungsdevice genutzt wird.\&lt;br /&gt;
Die Station 10418 (Lüdenscheid) überträgt aktuell am 09.03.2025 (noch) Rad1h.\&lt;br /&gt;
attr DWD downloadTimeout 120&lt;br /&gt;
attr DWD forecastDays 7&lt;br /&gt;
attr DWD forecastProperties SunUp, SunRise, SunSet, Rad1h, R101, RR1c, TTT, Tx, Tn, Tg, DD, FX1, RR6c, R600, RRhc, Rh00, ww, wwd, Neff&lt;br /&gt;
attr DWD forecastRefresh 1&lt;br /&gt;
attr DWD forecastResolution 1&lt;br /&gt;
attr DWD forecastStation 10418&lt;br /&gt;
attr DWD forecastWW2Text 1&lt;br /&gt;
attr DWD group Umwelt&lt;br /&gt;
attr DWD icon rc_WEB&lt;br /&gt;
attr DWD room 021_DWD&lt;br /&gt;
attr DWD stateFormat Tomorrow Tmax fc1_Tx °C on fc1_date at fc_description  -(state fc_time)&lt;br /&gt;
attr DWD verbose 2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== InverterDummy ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod InverterDummy dummy&lt;br /&gt;
attr InverterDummy event-on-change-reading .*&lt;br /&gt;
attr InverterDummy group Energy Meter&lt;br /&gt;
attr InverterDummy icon measure_photovoltaic_inst@green&lt;br /&gt;
attr InverterDummy room 020_PV,Energie&lt;br /&gt;
attr InverterDummy stateFormat {sprintf(&amp;quot;current %9.3f kW    Today_PVforecast  %9.3f kWh      Today_PV %9.3f kWh      Total_PV %9.3f kWh&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;total_pac&amp;quot;,0)/1,\&lt;br /&gt;
ReadingsNum(&amp;quot;Forecast&amp;quot;,&amp;quot;Today_PVforecast&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;etoday&amp;quot;,0)/1,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;etotal&amp;quot;,0)/1,)}&lt;br /&gt;
attr InverterDummy verbose 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SMA_Energymeter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod SMA_Energymeter SMAEM&lt;br /&gt;
attr SMA_Energymeter DbLogExclude state&lt;br /&gt;
attr SMA_Energymeter diffAccept 50&lt;br /&gt;
attr SMA_Energymeter disable 0&lt;br /&gt;
attr SMA_Energymeter disableSernoInReading 1&lt;br /&gt;
attr SMA_Energymeter event-on-update-reading state,Saldo_Wirkleistung,Bezug_Wirkleistung,Einspeisung_Wirkleistung,Bezug_Wirkleistung_Zaehler,Einspeisung_Wirkleistung_Zaehler&lt;br /&gt;
attr SMA_Energymeter feedinPrice 0.08&lt;br /&gt;
attr SMA_Energymeter group Energy Meter&lt;br /&gt;
attr SMA_Energymeter icon measure_power@green&lt;br /&gt;
attr SMA_Energymeter interval 15&lt;br /&gt;
attr SMA_Energymeter powerCost 0.25&lt;br /&gt;
attr SMA_Energymeter room 015_Zaehler,020_PV,Energie&lt;br /&gt;
attr SMA_Energymeter serialNumber XXXXXXXXXX&lt;br /&gt;
attr SMA_Energymeter stateFormat state W (IN -) P1: L1_Saldo_Wirkleistung P2: L2_Saldo_Wirkleistung P3:L3_Saldo_Wirkleistung&lt;br /&gt;
attr SMA_Energymeter verbose 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== BatteryDummy ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod BatteryDummy dummy&lt;br /&gt;
attr BatteryDummy DbLogExclude .*&lt;br /&gt;
attr BatteryDummy event-on-change-reading .*&lt;br /&gt;
attr BatteryDummy group Energy Meter&lt;br /&gt;
attr BatteryDummy icon batterie@green&lt;br /&gt;
attr BatteryDummy room 020_PV,Energie&lt;br /&gt;
attr BatteryDummy stateFormat {ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;total_pac&amp;quot;, undef).&amp;quot; kW &amp;quot;.\&lt;br /&gt;
&amp;quot; - total &amp;quot;.ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;bat_loadtotal&amp;quot;, undef).&amp;quot; kWh (-in)&amp;quot;.\&lt;br /&gt;
&amp;quot; - &amp;quot;.ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;bat_unloadtotal&amp;quot;, undef).&amp;quot; kWh (out)&amp;quot;.\&lt;br /&gt;
&amp;quot; - charged &amp;quot;.ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;chargestatus&amp;quot;, undef).&amp;quot; % &amp;quot;}&lt;br /&gt;
attr BatteryDummy userReadings total_pac, power_out, power_in, chargestatus, bat_rated_capacity, bat_loadtotal, bat_unloadtotal&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Berechnungs&amp;quot;-Notify der Werte für Batterie- und InverterDummy ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod N.PV.TotalConsumption.Dum.Energy notify SMA_Energymeter:Saldo_Wirkleistung:.* {\&lt;br /&gt;
 # Batterie-Bezug -Batterieentnahme\&lt;br /&gt;
fhem &amp;quot;setreading Dum.Energy BattLoadIn &amp;quot;.sprintf(&amp;quot;%.1f&amp;quot;,(ReadingsVal(&amp;quot;SBS25&amp;quot;,&amp;quot;power_out&amp;quot;,0)));;\&lt;br /&gt;
 # Batterie-Beladung Batterie mit Strom füllen\&lt;br /&gt;
fhem &amp;quot;setreading Dum.Energy BattLoadOut &amp;quot;.sprintf(&amp;quot;%.1f&amp;quot;,(ReadingsVal(&amp;quot;SBS25&amp;quot;,&amp;quot;power_in&amp;quot;,0)));;\&lt;br /&gt;
 # Batteriestatus\&lt;br /&gt;
fhem &amp;quot;setreading Dum.Energy BattStatusP &amp;quot;.sprintf(&amp;quot;%.1f&amp;quot;,(ReadingsVal(&amp;quot;SBS25&amp;quot;,&amp;quot;chargestatus&amp;quot;,0)));;\&lt;br /&gt;
 # Batterie-Bezug -Batterieentnahme_2\&lt;br /&gt;
fhem &amp;quot;setreading Dum.Energy BattLoadIn_2 &amp;quot;.sprintf(&amp;quot;%.1f&amp;quot;,(ReadingsVal(&amp;quot;SBS25_2&amp;quot;,&amp;quot;power_out&amp;quot;,0)));;\&lt;br /&gt;
 # Batterie-Beladung_2 Batterie mit Strom füllen\&lt;br /&gt;
fhem &amp;quot;setreading Dum.Energy BattLoadOut_2 &amp;quot;.sprintf(&amp;quot;%.1f&amp;quot;,(ReadingsVal(&amp;quot;SBS25_2&amp;quot;,&amp;quot;power_in&amp;quot;,0)));;\&lt;br /&gt;
 # Batteriestatus_2\&lt;br /&gt;
fhem &amp;quot;setreading Dum.Energy BattStatusP_2 &amp;quot;.sprintf(&amp;quot;%.1f&amp;quot;,(ReadingsVal(&amp;quot;SBS25_2&amp;quot;,&amp;quot;chargestatus&amp;quot;,0)));;\&lt;br /&gt;
 # Forecast Invertererzeugung InverterDummy \&lt;br /&gt;
fhem &amp;quot;setreading InverterDummy Today_PVforecast &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,(ReadingsNum(&amp;quot;Forecast&amp;quot;,&amp;quot;Today_PVforecast&amp;quot;,0)));;\&lt;br /&gt;
 # Invertererzeugung InverterDummy \&lt;br /&gt;
fhem &amp;quot;setreading InverterDummy etotal &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,(ReadingsNum(&amp;quot;SB25&amp;quot;,&amp;quot;etotal&amp;quot;,0))+(ReadingsNum(&amp;quot;SB30&amp;quot;,&amp;quot;etotal&amp;quot;,0))+(ReadingsNum(&amp;quot;SB40&amp;quot;,&amp;quot;etotal&amp;quot;,0)));;\&lt;br /&gt;
 # Invertererzeugung InverterDummy \&lt;br /&gt;
 #fhem &amp;quot;setreading InverterDummy total_pac &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,(ReadingsVal(&amp;quot;MB_USRW610_004&amp;quot;,&amp;quot;Power_Sum__W&amp;quot;,0)/1000)+(ReadingsNum(&amp;quot;SB25&amp;quot;,&amp;quot;total_pac&amp;quot;,0))+(ReadingsNum(&amp;quot;SB30&amp;quot;,&amp;quot;total_pac&amp;quot;,0))+(ReadingsNum(&amp;quot;SB40&amp;quot;,&amp;quot;total_pac&amp;quot;,0)));;\&lt;br /&gt;
fhem &amp;quot;setreading InverterDummy total_pac &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,(ReadingsNum(&amp;quot;SB25&amp;quot;,&amp;quot;total_pac&amp;quot;,0))+(ReadingsNum(&amp;quot;SB30&amp;quot;,&amp;quot;total_pac&amp;quot;,0))+(ReadingsNum(&amp;quot;SB40&amp;quot;,&amp;quot;total_pac&amp;quot;,0)));;\&lt;br /&gt;
#fhem &amp;quot;setreading InverterDummy total_pac &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,(ReadingsVal(&amp;quot;FCU&amp;quot;,&amp;quot;FCU-Strom-aktuelle-Leistung&amp;quot;,0)/1000)+(ReadingsNum(&amp;quot;SB25&amp;quot;,&amp;quot;total_pac&amp;quot;,0))+(ReadingsNum(&amp;quot;SB30&amp;quot;,&amp;quot;total_pac&amp;quot;,0))+(ReadingsNum(&amp;quot;SB40&amp;quot;,&amp;quot;total_pac&amp;quot;,0)));;\&lt;br /&gt;
 # Invertererzeugung InverterDummy \&lt;br /&gt;
my $wert1234 = &amp;quot;0&amp;quot; ;;\&lt;br /&gt;
$wert1234 = sprintf(&amp;quot;%.3f&amp;quot;,(ReadingsNum(&amp;quot;SB25&amp;quot;,&amp;quot;etoday&amp;quot;,0))+(ReadingsNum(&amp;quot;SB30&amp;quot;,&amp;quot;etoday&amp;quot;,0))+(ReadingsNum(&amp;quot;SB40&amp;quot;,&amp;quot;etoday&amp;quot;,0)));; \&lt;br /&gt;
fhem (&amp;quot;setreading InverterDummy etoday &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,$wert1234));;\&lt;br /&gt;
 # Batterie-Bezug -Batterieentnahme InverterDummy\&lt;br /&gt;
fhem &amp;quot;setreading BatteryDummy power_out &amp;quot;.sprintf(&amp;quot;%.0f&amp;quot;,(ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;power_out&amp;quot;,0))+(ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;power_out&amp;quot;,0)));;\&lt;br /&gt;
 # Batterie-Beladung InverterDummyBatterie mit Strom füllen\&lt;br /&gt;
fhem &amp;quot;setreading BatteryDummy power_in &amp;quot;.sprintf(&amp;quot;%.0f&amp;quot;,(ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;power_in&amp;quot;,0))+(ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;power_in&amp;quot;,0)));;\&lt;br /&gt;
 # Batterie-Bezug -bat_loadtotal Batterieentnahme InverterDummy\&lt;br /&gt;
fhem &amp;quot;setreading BatteryDummy bat_unloadtotal &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,(ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;bat_unloadtotal&amp;quot;,0))+(ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;bat_unloadtotal&amp;quot;,0)));;\&lt;br /&gt;
 # Batterie-Beladung bat_loadtotal InverterDummyBatterie mit Strom füllen\&lt;br /&gt;
fhem &amp;quot;setreading BatteryDummy bat_loadtotal &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,(ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;bat_loadtotal&amp;quot;,0))+(ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;bat_loadtotal&amp;quot;,0)));;\&lt;br /&gt;
 # Batteriestatus InverterDummy\&lt;br /&gt;
my $wert5 = sprintf(&amp;quot;%.2f&amp;quot;,(((ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;chargestatus&amp;quot;,0))/2) + ((ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;chargestatus&amp;quot;,0))/2)));; \&lt;br /&gt;
fhem (&amp;quot;setreading BatteryDummy chargestatus &amp;quot;.sprintf(&amp;quot;%.2f&amp;quot;,$wert5));;\&lt;br /&gt;
 # Batterie-total_pac  InverterDummy\&lt;br /&gt;
my $wert6 = sprintf(&amp;quot;%.3f&amp;quot;,((ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;total_pac&amp;quot;,0))+(ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;total_pac&amp;quot;,0))));; \&lt;br /&gt;
fhem (&amp;quot;setreading BatteryDummy total_pac &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,$wert6));;\&lt;br /&gt;
 # Batterie-total_pac  InverterDummy\&lt;br /&gt;
my $wert7 = sprintf(&amp;quot;%.3f&amp;quot;,((ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;bat_rated_capacity&amp;quot;,0))+(ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;bat_rated_capacity&amp;quot;,0))));; \&lt;br /&gt;
fhem (&amp;quot;setreading BatteryDummy bat_rated_capacity &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,$wert7));;\&lt;br /&gt;
 # möglicher Aufruf einer Batterie-Bebladung-Routine....SMABatteryChargewithTibber();;\&lt;br /&gt;
}&lt;br /&gt;
attr N.PV.TotalConsumption.Dum.Energy DbLogExclude .*&lt;br /&gt;
attr N.PV.TotalConsumption.Dum.Energy room Energie&lt;br /&gt;
attr N.PV.TotalConsumption.Dum.Energy verbose 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SolarForecast ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Forecast SolarForecast&lt;br /&gt;
attr Forecast DbLogExclude .*&lt;br /&gt;
attr Forecast DbLogInclude Current_BatCharge999&lt;br /&gt;
attr Forecast affectBatteryPreferredCharge 30&lt;br /&gt;
attr Forecast affectConsForecastLastDays 31&lt;br /&gt;
attr Forecast affect70percentRule 0&lt;br /&gt;
attr Forecast comment &amp;quot;wget -qO ./FHEM/76_SolarForecast.pm https://svn.fhem.de/fhem/trunk/fhem/contrib/DS_Starter/76_SolarForecast.pm&amp;quot;\&lt;br /&gt;
&amp;quot;wget -qO ./FHEM/55_DWD_OpenData.pm https://svn.fhem.de/fhem/trunk/fhem/contrib/DS_Starter/55_DWD_OpenData.pm&amp;quot;\&lt;br /&gt;
&amp;quot;13.01.2025 mit der Version 76_SolarForecast.pm:v1.43.2-s29518/2025-01-12&amp;quot;&lt;br /&gt;
attr Forecast graphicHeaderOwnspec PV&amp;amp;nbsp;;Heute&amp;amp;nbsp;;real:Today_PVreal Verbrauch&amp;amp;nbsp;;bis&amp;amp;nbsp;;Sonnenaufgang&amp;amp;nbsp;;:special_conForecastTillNextSunrise PV&amp;amp;nbsp;;Morgen&amp;amp;nbsp;;erwartet:Tomorrow_PVforecast PV&amp;amp;nbsp;;Uebermorgen&amp;amp;nbsp;;erwartet:special_dayAfterTomorrowPVforecast  Batt.-Ladeanforderung&amp;amp;nbsp;;:Battery_ChargeRequest FCU-Erzeugung&amp;amp;nbsp;;:Current_PP01\&lt;br /&gt;
attr Forecast consumer01 FBDECT_fbahahttp_11657_0127183 icon=scene_washing_machine@orange type=washingmachine power=10 swstate:state notbefore=09 notafter=20 pcurr=power:W:3 etotal=energy:Wh interruptable=1 auto=solarforecast_auto surpmeth=default&lt;br /&gt;
attr Forecast consumer02 FBDECT_fbahahttp_E8_DF_70_07_3E_57 icon=light_floor_lamp@orange type=other power=15 swstate:state pcurr=power:W:10 etotal=energy:Wh interruptable=0 auto=solarforecast_auto surpmeth=default&lt;br /&gt;
attr Forecast consumer03 FBDECT_fbahahttp_E8_DF_70_07_42_0B icon=raspberrypi@orange type=other power=8 swstate:state pcurr=power:W:1 etotal=energy:Wh interruptable=0 auto=solarforecast_auto surpmeth=default&lt;br /&gt;
attr Forecast consumer04 FBDECT_fbahahttp_11657_0067275 icon=springbrunnen_icon@orange type=other power=50 swstate:state pcurr=power:W:10 etotal=energy:Wh interruptable=0 auto=solarforecast_auto surpmeth=default&lt;br /&gt;
attr Forecast consumer05 FBDECT_fbahahttp_34_31_C4_D4_31_37 icon=sani_domestic_waterworks@orange type=other power=10 swstate:state pcurr=power:W:3 etotal=energy:Wh auto=solarforecast_auto surpmeth=default&lt;br /&gt;
attr Forecast consumer06 tuya_local_bf5037060f450bdbd4rl0q icon=scene_clothes_dryer@orange type=dryer power=10 swstate:state pcurr=cur_power:W:3 etotal=energy:Wh auto=solarforecast_auto surpmeth=default&lt;br /&gt;
attr Forecast consumer07 tuya_local_bfac44fb487476efd1vhdu icon=weather_sunset@orange type=noSchedule power=5 swstate:state pcurr=cur_power:W:3 etotal=energy:Wh auto=solarforecast_auto surpmeth=default&lt;br /&gt;
attr Forecast consumerControl adviceIcon=light_light_dim_100@gold&lt;br /&gt;
attr Forecast consumerControl showLegend=icon_top&lt;br /&gt;
attr Forecast consumerControl detailLink=1&lt;br /&gt;
attr Forecast ctrlAIdataStorageDuration 1825&lt;br /&gt;
attr Forecast ctrlAIshiftTrainStart 2&lt;br /&gt;
attr Forecast ctrlBatSocManagement01 lowSoc=10 upSoC=30 maxSoC=99 careCycle=20&lt;br /&gt;
attr Forecast ctrlBatSocManagement02 lowSoc=10 upSoC=30 maxSoC=99 careCycle=20&lt;br /&gt;
attr Forecast ctrlDebug none&lt;br /&gt;
attr Forecast plantControl genPVdeviation=continuously&lt;br /&gt;
attr Forecast plantControl cycleInterval=15&lt;br /&gt;
attr Forecast ctrlNextDayForecastReadings 01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24&lt;br /&gt;
attr Forecast ctrlNextHoursSoCForecastReadings 00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23&lt;br /&gt;
attr Forecast ctrlSpecialReadings BatPowerIn_Sum,BatPowerOut_Sum,SunHours_Remain,SunMinutes_Remain,allStringsFullfilled,conForecastTillNextSunrise,currentAPIinterval,currentRunMtsConsumer_01,currentRunMtsConsumer_02,currentRunMtsConsumer_03,currentRunMtsConsumer_04,currentRunMtsConsumer_05,currentRunMtsConsumer_06,currentRunMtsConsumer_07,dayAfterTomorrowPVforecast,daysUntilBatteryCare_01,daysUntilBatteryCare_02,lastretrieval_time,lastretrieval_timestamp,response_message,runTimeAvgDayConsumer_01,runTimeAvgDayConsumer_02,runTimeAvgDayConsumer_03,runTimeAvgDayConsumer_04,runTimeAvgDayConsumer_05,runTimeAvgDayConsumer_06,runTimeAvgDayConsumer_07,runTimeCentralTask,runTimeLastAPIAnswer,runTimeLastAPIProc,runTimeTrainAI,todayBatIn_01,todayBatIn_02,todayBatOut_01,todayBatOut_02,todayConForecastTillSunset,todayConsumptionForecast,todayDoneAPIcalls,todayDoneAPIrequests,todayGridConsumption,todayGridFeedIn,todayMaxAPIcalls,todayRemainingAPIcalls,todayRemainingAPIrequests&lt;br /&gt;
attr Forecast disable 0&lt;br /&gt;
attr Forecast event-min-interval .*:1800&lt;br /&gt;
attr Forecast event-on-change-reading .*&lt;br /&gt;
attr Forecast flowGraphicControl animate=1 consumerdist=80 h2consumerdist=50 shiftx=0  shifty=0 showconsumer=1 showconsumerdummy=1 showconsumerpower=1 showconsumerremaintime=0 size=400 strokewidth=12&lt;br /&gt;
attr Forecast graphicBeam1Color 3C14FF&lt;br /&gt;
attr Forecast graphicBeam1Content pvReal&lt;br /&gt;
attr Forecast graphicBeam2Color 19FF29&lt;br /&gt;
attr Forecast graphicBeam2Content pvForecast&lt;br /&gt;
attr Forecast graphicBeam3Color D60924&lt;br /&gt;
attr Forecast graphicBeam3Content batsocforecast_02&lt;br /&gt;
attr Forecast graphicBeam3FontColor FFFF0D&lt;br /&gt;
attr Forecast graphicBeam4Color FFFF1F&lt;br /&gt;
attr Forecast graphicBeam4Content batsocforecast_01&lt;br /&gt;
attr Forecast graphicBeam4FontColor 000000&lt;br /&gt;
attr Forecast graphicBeamHeightLevel1 200&lt;br /&gt;
attr Forecast graphicBeamHeightLevel2 200&lt;br /&gt;
attr Forecast graphicHeaderDetail all&lt;br /&gt;
attr Forecast graphicHeaderOwnspec #PV\&lt;br /&gt;
PV&amp;amp;nbsp;;Heute&amp;amp;nbsp;;real:Today_PVreal\&lt;br /&gt;
PV&amp;amp;nbsp;;Morgen&amp;amp;nbsp;;erwartet:Tomorrow_PVforecast\&lt;br /&gt;
PV&amp;amp;nbsp;;Uebermorgen&amp;amp;nbsp;;erwartet:special_dayAfterTomorrowPVforecast\&lt;br /&gt;
:\&lt;br /&gt;
#\&lt;br /&gt;
AutarkyRate:Current_AutarkyRate\&lt;br /&gt;
Überschuss:Current_Surplus\&lt;br /&gt;
aktueller&amp;amp;nbsp;;Netzbezug:Current_GridConsumption\&lt;br /&gt;
:\&lt;br /&gt;
#Verbrauch\&lt;br /&gt;
bis&amp;amp;nbsp;;Sonnenuntergang:special_todayConForecastTillSunset\&lt;br /&gt;
bis&amp;amp;nbsp;;Sonnenaufgang&amp;amp;nbsp;;:special_conForecastTillNextSunrise\&lt;br /&gt;
:\&lt;br /&gt;
:\&lt;br /&gt;
#Batterie01\&lt;br /&gt;
Batt.-Ladeanforderung&amp;amp;nbsp;;:Battery_ChargeRequest_01\&lt;br /&gt;
Batt.-Ladung&amp;amp;nbsp;;empfohlen:Battery_ChargeUnrestricted_01\&lt;br /&gt;
Ladung&amp;amp;nbsp;;heute:special_todayBatIn_01\&lt;br /&gt;
Entladung&amp;amp;nbsp;;heute:special_todayBatOut_01\&lt;br /&gt;
#Batterie01_tmp\&lt;br /&gt;
Current_PowerBatIn_01:Current_PowerBatIn_01\&lt;br /&gt;
Current_PowerBatOut_01:Current_PowerBatOut_01\&lt;br /&gt;
:\&lt;br /&gt;
:\&lt;br /&gt;
#Batterie02\&lt;br /&gt;
Batt.-Ladeanforderung&amp;amp;nbsp;;:Battery_ChargeRequest_02\&lt;br /&gt;
Batt.-Ladung&amp;amp;nbsp;;empfohlen:Battery_ChargeUnrestricted_02\&lt;br /&gt;
Ladung&amp;amp;nbsp;;heute:special_todayBatIn_02\&lt;br /&gt;
Entladung&amp;amp;nbsp;;heute:special_todayBatOut_02\&lt;br /&gt;
#Batterie02_tmp\&lt;br /&gt;
Current_PowerBatIn_02:Current_PowerBatIn_02\&lt;br /&gt;
Current_PowerBatOut_02:Current_PowerBatOut_02\&lt;br /&gt;
:\&lt;br /&gt;
:\&lt;br /&gt;
#Settings\&lt;br /&gt;
Autokorrektur:pvCorrectionFactor_Auto \&lt;br /&gt;
Wetter:graphicShowWeather\&lt;br /&gt;
History:graphicHistoryHour\&lt;br /&gt;
ShowNight:graphicShowNight\&lt;br /&gt;
Debug:ctrlDebug\&lt;br /&gt;
FCU-Modus:FCU-Betriebsmodus@FCU&lt;br /&gt;
attr Forecast graphicHistoryHour 4&lt;br /&gt;
attr Forecast graphicHourCount 24&lt;br /&gt;
attr Forecast graphicLayoutType double&lt;br /&gt;
attr Forecast graphicShowDiff top&lt;br /&gt;
attr Forecast graphicShowNight 1&lt;br /&gt;
attr Forecast graphicShowWeather 1&lt;br /&gt;
attr Forecast group Energy Meter&lt;br /&gt;
attr Forecast room 020_PV,Energie&lt;br /&gt;
attr Forecast setupBatteryDev01 SBS25 pin=-pout:kW pout=total_pac:kW intotal=bat_loadtotal:kWh outtotal=bat_unloadtotal:kWh charge=chargestatus cap=9800 show=2&lt;br /&gt;
attr Forecast setupBatteryDev02 SBS25_2 pin=-pout:kW pout=total_pac:kW intotal=bat_loadtotal:kWh outtotal=bat_unloadtotal:kWh charge=chargestatus cap=9800 show=2&lt;br /&gt;
attr Forecast setupInverterDev01 SB25 pv=total_pac:kW etotal=etotal:kWh capacity=2500 strings=GarageSE limit=70&lt;br /&gt;
attr Forecast setupInverterDev02 SB30 pv=total_pac:kW etotal=etotal:kWh capacity=3000 strings=GarageNW,HausNW limit=70&lt;br /&gt;
attr Forecast setupInverterDev03 SB40 pv=total_pac:kW etotal=etotal:kWh capacity=4000 strings=HausSE1,HausSE2,HausSW limit=70&lt;br /&gt;
attr Forecast setupInverterStrings GarageSE,GarageNW,HausNW,HausSW,HausSE1,HausSE2&lt;br /&gt;
attr Forecast setupMeterDev SMA_Energymeter gcon=Bezug_Wirkleistung:W contotal=Bezug_Wirkleistung_Zaehler:kWh gfeedin=Einspeisung_Wirkleistung:W feedtotal=Einspeisung_Wirkleistung_Zaehler:kWh conprice=0.25:€ feedprice=0.08123:€&lt;br /&gt;
attr Forecast setupOtherProducer01 icon=Heizung_FCU_green@red MB_USRW610_004 pcurr=Power_L1__W:W etotal=Energy_L1_import__kWh:kWh&lt;br /&gt;
attr Forecast setupRadiationAPI DWD&lt;br /&gt;
attr Forecast setupStringPeak GarageSE=2.75 GarageNW=3.200 HausNW=2.230 HausSW=2.230 HausSE1=2.200 HausSE2=2.200&lt;br /&gt;
attr Forecast setupWeatherDev1 DWD&lt;br /&gt;
attr Forecast stateFormat Current_PV&lt;br /&gt;
attr Forecast userReadings Current_BatCharge999 {((ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;chargestatus&amp;quot;,0) * 10 * ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;bat_rated_capacity&amp;quot;,0))  + (ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;chargestatus&amp;quot;,0) * 10 * ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;bat_rated_capacity&amp;quot;,0))) / ( (ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;bat_rated_capacity&amp;quot;,0) * 1000)  + (ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;bat_rated_capacity&amp;quot;,0)*1000))*100}&lt;br /&gt;
attr Forecast verbose 2&lt;br /&gt;
&lt;br /&gt;
setstate Forecast 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:55 .FCU_FCU-Betriebsmodus 2&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:55 .Forecast_ctrlDebug none&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:55 .Forecast_graphicHistoryHour 4&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:55 .Forecast_graphicShowNight 1&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:55 .Forecast_graphicShowWeather 1&lt;br /&gt;
setstate Forecast 2025-01-13 08:24:25 .associatedWith SMA_Energymeter FBDECT_fbahahttp_11657_0127183 FBDECT_fbahahttp_E8_DF_70_07_3E_57 FBDECT_fbahahttp_E8_DF_70_07_42_0B FBDECT_fbahahttp_11657_0067275 FBDECT_fbahahttp_34_31_C4_D4_31_37 tuya_local_bf5037060f450bdbd4rl0q tuya_local_bfac44fb487476efd1vhdu SBS25 SBS25_2 SB25 SB30 SB40 DWD MB_USRW610_004&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 .lastupdateForecastValues 1736790834&lt;br /&gt;
setstate Forecast 2025-01-13 01:00:05 .pvCorrectionFactor_01_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 01:00:05 .pvCorrectionFactor_01_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 02:00:04 .pvCorrectionFactor_02_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 02:00:04 .pvCorrectionFactor_02_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 03:00:04 .pvCorrectionFactor_03_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 03:00:04 .pvCorrectionFactor_03_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 04:00:05 .pvCorrectionFactor_04_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 04:00:05 .pvCorrectionFactor_04_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 05:00:05 .pvCorrectionFactor_05_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 05:00:05 .pvCorrectionFactor_05_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 06:00:06 .pvCorrectionFactor_06_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 06:00:06 .pvCorrectionFactor_06_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 07:00:04 .pvCorrectionFactor_07_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 07:00:04 .pvCorrectionFactor_07_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 08:00:03 .pvCorrectionFactor_08_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 08:00:03 .pvCorrectionFactor_08_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 09:00:04 .pvCorrectionFactor_09_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 09:00:04 .pvCorrectionFactor_09_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 10:00:05 .pvCorrectionFactor_10_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 10:00:05 .pvCorrectionFactor_10_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 11:00:05 .pvCorrectionFactor_11_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 11:00:05 .pvCorrectionFactor_11_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 12:00:02 .pvCorrectionFactor_12_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 12:00:02 .pvCorrectionFactor_12_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 13:00:02 .pvCorrectionFactor_13_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 13:00:02 .pvCorrectionFactor_13_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 14:00:03 .pvCorrectionFactor_14_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 14:00:03 .pvCorrectionFactor_14_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 15:00:05 .pvCorrectionFactor_15_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 15:00:05 .pvCorrectionFactor_15_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 16:00:06 .pvCorrectionFactor_16_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 16:00:06 .pvCorrectionFactor_16_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 17:00:05 .pvCorrectionFactor_17_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 17:00:05 .pvCorrectionFactor_17_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 18:00:04 .pvCorrectionFactor_18_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 18:00:04 .pvCorrectionFactor_18_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 .pvCorrectionFactor_Auto_Soll on_complex_ai&lt;br /&gt;
setstate Forecast 2025-01-13 01:00:05 .signaldone_01 done&lt;br /&gt;
setstate Forecast 2025-01-13 02:00:04 .signaldone_02 done&lt;br /&gt;
setstate Forecast 2025-01-13 03:00:04 .signaldone_03 done&lt;br /&gt;
setstate Forecast 2025-01-13 04:00:05 .signaldone_04 done&lt;br /&gt;
setstate Forecast 2025-01-13 05:00:05 .signaldone_05 done&lt;br /&gt;
setstate Forecast 2025-01-13 06:00:06 .signaldone_06 done&lt;br /&gt;
setstate Forecast 2025-01-13 07:00:04 .signaldone_07 done&lt;br /&gt;
setstate Forecast 2025-01-13 08:00:03 .signaldone_08 done&lt;br /&gt;
setstate Forecast 2025-01-13 09:00:04 .signaldone_09 done&lt;br /&gt;
setstate Forecast 2025-01-13 10:00:05 .signaldone_10 done&lt;br /&gt;
setstate Forecast 2025-01-13 11:00:05 .signaldone_11 done&lt;br /&gt;
setstate Forecast 2025-01-13 12:00:02 .signaldone_12 done&lt;br /&gt;
setstate Forecast 2025-01-13 13:00:02 .signaldone_13 done&lt;br /&gt;
setstate Forecast 2025-01-13 14:00:03 .signaldone_14 done&lt;br /&gt;
setstate Forecast 2025-01-13 15:00:05 .signaldone_15 done&lt;br /&gt;
setstate Forecast 2025-01-13 16:00:06 .signaldone_16 done&lt;br /&gt;
setstate Forecast 2025-01-13 17:00:05 .signaldone_17 done&lt;br /&gt;
setstate Forecast 2025-01-13 18:00:04 .signaldone_18 done&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_ChargeUnrestricted_01 1&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_ChargeUnrestricted_02 1&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_ChargeRequest_01 1&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_ChargeRequest_02 1&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour00_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour00_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour01_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour01_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour02_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour02_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour03_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour03_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour04_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour04_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour05_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour05_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour06_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour06_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour07_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour07_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour08_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour08_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour09_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour09_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour10_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour10_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour11_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour11_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour12_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour12_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour13_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour13_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour14_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour14_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour15_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour15_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour16_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour16_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour17_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour17_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour18_SoCforecast_01 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour18_SoCforecast_02 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour19_SoCforecast_01 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour19_SoCforecast_02 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour20_SoCforecast_01 42.6 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour20_SoCforecast_02 42.6 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour21_SoCforecast_01 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour21_SoCforecast_02 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour22_SoCforecast_01 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour22_SoCforecast_02 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour23_SoCforecast_01 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour23_SoCforecast_02 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_OptimumTargetSoC_01 40 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_OptimumTargetSoC_02 40 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_AutarkyRate 83 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:55 Current_BatCharge999 10&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_BatCharge_01 12 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_BatCharge_02 8 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_Consumption 626 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_GridConsumption 2 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_GridFeedIn 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_PP_01 746.0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_PV 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_PowerBatIn_01 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_PowerBatIn_02 132 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_PowerBatOut_01 10 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_PowerBatOut_02 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_SelfConsumption 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_SelfConsumptionRate 0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_Surplus 120 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:00:00 LastHourGridconsumptionReal 5 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:00:00 LastHourPVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:00:00 LastHourPVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 NextHours_Sum01_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 NextHours_Sum02_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 NextHours_Sum03_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 NextHours_Sum04_ConsumptionForecast 2944 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 NextHours_Sum04_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 RestOfDayConsumptionForecast 3609 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 RestOfDayPVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 Today_Hour01_BatIn_01 272 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 Today_Hour01_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 Today_Hour01_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 Today_Hour01_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 Today_Hour01_GridConsumption 1 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 Today_Hour01_GridFeedIn 1 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 Today_Hour01_PPreal_01 748 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 Today_Hour01_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 Today_Hour02_BatIn_01 266 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 Today_Hour02_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 Today_Hour02_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 Today_Hour02_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 Today_Hour02_GridConsumption 1 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 Today_Hour02_GridFeedIn 1 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 Today_Hour02_PPreal_01 787 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 Today_Hour02_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 Today_Hour03_BatIn_01 271 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 Today_Hour03_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 Today_Hour03_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 Today_Hour03_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 Today_Hour03_GridConsumption 2 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 Today_Hour03_GridFeedIn 2 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 Today_Hour03_PPreal_01 750 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 Today_Hour03_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 Today_Hour04_BatIn_01 266 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 Today_Hour04_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 Today_Hour04_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 Today_Hour04_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 Today_Hour04_GridConsumption 1 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 Today_Hour04_GridFeedIn 1 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 Today_Hour04_PPreal_01 745 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 Today_Hour04_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 Today_Hour05_BatIn_01 267 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 Today_Hour05_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 Today_Hour05_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 Today_Hour05_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 Today_Hour05_GridConsumption 2 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 Today_Hour05_GridFeedIn 2 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 Today_Hour05_PPreal_01 758 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 Today_Hour05_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 Today_Hour06_BatIn_01 255 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 Today_Hour06_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 Today_Hour06_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 Today_Hour06_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 Today_Hour06_GridConsumption 1 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 Today_Hour06_GridFeedIn 1 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 Today_Hour06_PPreal_01 752 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 Today_Hour06_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 Today_Hour07_BatIn_01 226 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 Today_Hour07_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 Today_Hour07_BatOut_01 50 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 Today_Hour07_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 Today_Hour07_GridConsumption 2 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 Today_Hour07_GridFeedIn 2 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 Today_Hour07_PPreal_01 681 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 Today_Hour07_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 Today_Hour08_BatIn_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 Today_Hour08_BatIn_02 233 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 Today_Hour08_BatOut_01 845 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 Today_Hour08_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 Today_Hour08_GridConsumption 4 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 Today_Hour08_GridFeedIn 4 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 Today_Hour08_PPreal_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 Today_Hour08_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_BatIn_01 37 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_BatIn_02 90 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_BatOut_01 351 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_BatOut_02 188 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_GridConsumption 447 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_GridFeedIn 4 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_PPreal_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_PVforecast 127 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_BatIn_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_GridConsumption 1650 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_GridFeedIn 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_PPreal_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_PVforecast 478 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_PVreal 26 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_BatIn_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_GridConsumption 513 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_GridFeedIn 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_PPreal_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_PVforecast 868 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_PVreal 97 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_BatIn_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_GridConsumption 576 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_GridFeedIn 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_PPreal_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_PVforecast 1157 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_PVreal 320 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_BatIn_01 8 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_BatIn_02 4 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_GridConsumption 1272 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_GridFeedIn 7 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_PPreal_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_PVforecast 1238 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_PVreal 945 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_BatIn_01 410 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_BatIn_02 53 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_GridConsumption 955 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_GridFeedIn 31 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_PPreal_01 562 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_PVforecast 1168 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_PVreal 1410 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_BatIn_01 703 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_BatIn_02 500 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_BatOut_01 22 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_BatOut_02 18 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_GridConsumption 32 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_GridFeedIn 71 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_PPreal_01 777 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_PVforecast 1630 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_PVreal 1416 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_BatIn_01 296 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_BatIn_02 70 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_BatOut_01 74 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_BatOut_02 258 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_GridConsumption 13 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_GridFeedIn 17 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_PPreal_01 732 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_PVforecast 880 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_PVreal 1051 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_BatIn_01 47 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_BatIn_02 126 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_BatOut_01 102 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_BatOut_02 75 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_GridConsumption 15 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_GridFeedIn 23 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_PPreal_01 771 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_PVforecast 117 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_PVreal 86 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 Today_Hour18_BatIn_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 Today_Hour18_BatIn_02 410 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 Today_Hour18_BatOut_01 758 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 Today_Hour18_BatOut_02 67 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 Today_Hour18_GridConsumption 5 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 Today_Hour18_GridFeedIn 5 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 Today_Hour18_PPreal_01 723 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 Today_Hour18_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_Hour19_BatIn_01 349 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_Hour19_BatIn_02 124 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_Hour19_BatOut_01 73 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_Hour19_BatOut_02 450 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_Hour19_GridConsumption 8 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_Hour19_GridFeedIn 6 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_Hour19_PPreal_01 671 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_Hour19_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_MaxPVforecast 1630 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_MaxPVforecastTime 2025-01-13 14:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_PVdeviation 30.17 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_PVforecast 7663 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_PVreal 5351 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_SunRise 08:28&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_SunSet 16:46&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_ConsumptionForecast 17043 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour01_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour02_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour03_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour04_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour05_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour06_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour07_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour08_PVforecast 10 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour09_PVforecast 161 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour10_PVforecast 275 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour11_PVforecast 532 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour12_PVforecast 730 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour13_PVforecast 1252 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour14_PVforecast 818 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour15_PVforecast 1465 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour16_PVforecast 303 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour17_PVforecast 20 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour18_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour19_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour20_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour21_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour22_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour23_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour24_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_PVforecast 5566 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_SunRise 08:27&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_SunSet 16:47&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer01 name=&#039;_Waschmaschine&#039; state=&#039;off&#039; mode=&#039;can&#039; planningstate=&#039;planned&#039;&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer01_currentPower 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer01_planned_start 14.01.2025 09:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer01_planned_stop 14.01.2025 11:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer02 name=&#039;_Esszimmer&#039; state=&#039;on&#039; mode=&#039;can&#039; planningstate=&#039;planned&#039;&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer02_currentPower 15.3 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer02_planned_start 14.01.2025 08:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer02_planned_stop 14.01.2025 09:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer03 name=&#039;_FCU&#039; state=&#039;on&#039; mode=&#039;can&#039; planningstate=&#039;planned&#039;&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer03_currentPower 7.15 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer03_planned_start 14.01.2025 07:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer03_planned_stop 14.01.2025 08:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer04 name=&#039;_Brunnen&#039; state=&#039;off&#039; mode=&#039;can&#039; planningstate=&#039;planned&#039;&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer04_currentPower 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer04_planned_start 14.01.2025 08:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer04_planned_stop 14.01.2025 09:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer05 name=&#039;_Zisterne&#039; state=&#039;off&#039; mode=&#039;can&#039; planningstate=&#039;planned&#039;&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer05_currentPower 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer05_planned_start 14.01.2025 07:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer05_planned_stop 14.01.2025 08:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer06 name=&#039;SW Trockner&#039; state=&#039;unknown&#039; mode=&#039;can&#039; planningstate=&#039;planned&#039;&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer06_currentPower 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer06_planned_start 14.01.2025 07:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer06_planned_stop 14.01.2025 08:30:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer07 name=&#039;SW Urlaubslicht-Wohnzimmer&#039; state=&#039;on&#039; mode=&#039;can&#039; planningstate=&#039;noSchedule&#039; info=&#039;von extern umgeschaltet&#039;&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer07_currentPower 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 nextCycletime 18:54:09&lt;br /&gt;
setstate Forecast 2025-01-13 10:00:05 pvCorrectionFactor_10 0.53 (automatic - old factor: 1.00, Sun Alt range: 5, Cloud range: 75, Days in range: 1)&lt;br /&gt;
setstate Forecast 2025-01-13 11:00:05 pvCorrectionFactor_11 0.56 (automatic - old factor: 1.00, Sun Alt range: 10, Cloud range: 70, Days in range: 1)&lt;br /&gt;
setstate Forecast 2025-01-13 12:00:02 pvCorrectionFactor_12 0.64 (automatic - old factor: 1.00, Sun Alt range: 15, Cloud range: 60, Days in range: 1)&lt;br /&gt;
setstate Forecast 2025-01-13 13:00:02 pvCorrectionFactor_13 0.88 (automatic - old factor: 1.00, Sun Alt range: 15, Cloud range: 60, Days in range: 1)&lt;br /&gt;
setstate Forecast 2025-01-13 14:00:03 pvCorrectionFactor_14 1.10 (automatic - old factor: 1.00, Sun Alt range: 15, Cloud range: 50, Days in range: 1)&lt;br /&gt;
setstate Forecast 2025-01-13 15:00:05 pvCorrectionFactor_15 1.01 (automatic - old factor: 1.06, Sun Alt range: 15, Cloud range: 45, Days in range: 2)&lt;br /&gt;
setstate Forecast 2025-01-13 16:00:06 pvCorrectionFactor_16 1.09 (automatic - old factor: 1.00, Sun Alt range: 10, Cloud range: 45, Days in range: 1)&lt;br /&gt;
setstate Forecast 2025-01-13 17:00:05 pvCorrectionFactor_17 0.28 (automatic - old factor: 0.52, Sun Alt range: 0, Cloud range: 45, Days in range: 2)&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 pvCorrectionFactor_Auto on_complex_ai&lt;br /&gt;
setstate Forecast 2024-10-30 19:42:19 setupStringAzimuth GarageSE=-55 GarageNW=125 HausNW=125 HausSW=35 HausSE1=-55 HausSE2=-55&lt;br /&gt;
setstate Forecast 2024-10-30 19:37:38 setupStringDeclination GarageSE=40 GarageNW=40 HausNW=50 HausSW=50 HausSE1=50 HausSE2=50&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_BatPowerIn_Sum 132 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_BatPowerOut_Sum 10 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_SunHours_Remain 0.00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_SunMinutes_Remain 0&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_allStringsFullfilled 1&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_conForecastTillNextSunrise 9467 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_currentAPIinterval 0&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_currentRunMtsConsumer_01 132 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_currentRunMtsConsumer_02 184 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_currentRunMtsConsumer_03 329512 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_currentRunMtsConsumer_04 200 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_currentRunMtsConsumer_05 27 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_currentRunMtsConsumer_06 193 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_currentRunMtsConsumer_07 106 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_dayAfterTomorrowPVforecast 7344 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_daysUntilBatteryCare_01 12&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_daysUntilBatteryCare_02 12&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_lastretrieval_time 2025-01-13 18:53:54&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_lastretrieval_timestamp 1736790834&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_response_message success&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeAvgDayConsumer_01 545.94 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeAvgDayConsumer_02 382.10 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeAvgDayConsumer_03 1430.13 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeAvgDayConsumer_04 262.05 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeAvgDayConsumer_05 28.80 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeAvgDayConsumer_06 622.63 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeAvgDayConsumer_07 276.51 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeCentralTask 0.3744&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeLastAPIAnswer -&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeLastAPIProc -&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeTrainAI 1.2529&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayBatIn_01 3683.0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayBatIn_02 1617.0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayBatOut_01 2287.0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayBatOut_02 1057.0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayConForecastTillSunset 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 special_todayConsumptionForecast_01 509 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 special_todayConsumptionForecast_02 499 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 special_todayConsumptionForecast_03 501 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 special_todayConsumptionForecast_04 511 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 special_todayConsumptionForecast_05 503 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 special_todayConsumptionForecast_06 495 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 special_todayConsumptionForecast_07 504 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 special_todayConsumptionForecast_08 561 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 special_todayConsumptionForecast_09 768 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 special_todayConsumptionForecast_10 783 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 special_todayConsumptionForecast_11 692 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 special_todayConsumptionForecast_12 791 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 special_todayConsumptionForecast_13 910 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 special_todayConsumptionForecast_14 1022 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 special_todayConsumptionForecast_15 965 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 special_todayConsumptionForecast_16 812 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 special_todayConsumptionForecast_17 884 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 special_todayConsumptionForecast_18 928 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayConsumptionForecast_19 874 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayConsumptionForecast_20 763 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayConsumptionForecast_21 750 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayConsumptionForecast_22 765 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayConsumptionForecast_23 643 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayConsumptionForecast_24 601 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayDoneAPIcalls 0&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayDoneAPIrequests 4532&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayGridConsumption 5500.9 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayGridFeedIn 178.9 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayMaxAPIcalls n.a.&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayRemainingAPIcalls n.a.&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayRemainingAPIrequests n.a.&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:55 state updated&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
So sollte es dann als Ergebnis aussehen:&lt;br /&gt;
[[Datei:Bildschirmfoto 2025-01-13.png|zentriert|mini|Ergebnis nach kompletter Einrichtung]]&lt;br /&gt;
[[Datei:Bildschirmfoto 2025-01-13 Teil II.png|alternativtext=Unterer Teil der Anzeige|zentriert|mini]]&lt;br /&gt;
&lt;br /&gt;
== Praxisbeispiele und Lösungsansätze für Steuerungen ==&lt;br /&gt;
=== Fallstudie: Trockner darf pausiert werden, wenn nicht genug PV-Überschuss vorhanden ist, soll aber nach spätestens X Stunden fertig sein ===&lt;br /&gt;
Für diese Aufgabenstellung sind mehrere Schlüssel essentiell wichtig, &#039;&#039;&#039;power&#039;&#039;&#039;, &#039;&#039;&#039;mintime&#039;&#039;&#039;, &#039;&#039;&#039;mode&#039;&#039;&#039; und &#039;&#039;&#039;interruptable&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Die Bedingung, dass der Trockner nach spätestens X Stunden fertig sein soll, steht in einem Widerspruch zu der Möglichkeit den Trockner bei zu wenig PV-Überschuss unterbrechen zu können. Im Extremfall könnte nach dem Start die gesamte Planungszeit ungenügender Überschuss vorliegen und der Trockner nicht arbeiten. Der Schlüssel &#039;&#039;&#039;mintime&#039;&#039;&#039; (in Minuten) wird nun wie folgt angesetzt:&lt;br /&gt;
&lt;br /&gt;
 mintime = 2,5 x &amp;lt;gewöhnliche Betriebszeit für einen Trockengang (mneed, z.B. 120)&amp;gt; = 300 Minuten&lt;br /&gt;
&lt;br /&gt;
Das bedeutet, der Trockner wird nach 300 Minuten Laufzeit abgeschaltet werden bzw. vom Netz getrennt. Der Trockenvorgang wird natürlich bereits nach 120 Minuten beendet sein, sofern nach Start keine Unterbrechnung des Vorganges erfolgte. Wurde der Vorgang unterbrochen, soll der Trockner innerhalb &lt;br /&gt;
&lt;br /&gt;
 X+120 bis X+300 &lt;br /&gt;
&lt;br /&gt;
fertig sein. &lt;br /&gt;
&lt;br /&gt;
Demnach ist die ausgeführte Laufzeit des Trockners permanent zu überwachen, zu summieren (rtsum) und die notwendige Restzeit (mneed - rtsum) mit der noch verbleibenden Restzeit (mrest) bis zur geplanten Abschaltung des Consumers zu vergleichen. Ist der Consumer gestartet, wird die Laufzeit in der pvHistory für jede Stunde des Tages im Schlüssel &#039;&#039;minutescsmXX&#039;&#039; (XX = Consumernummer) aufgezeichnet und kann darüber ausgewertet werden. Somit ist:&lt;br /&gt;
&lt;br /&gt;
 msum = for (01 .. 24) {Summe von minutescsmXX} des aktuellen Tages&lt;br /&gt;
&lt;br /&gt;
Solange die Bedingung &lt;br /&gt;
&lt;br /&gt;
 mrest &amp;gt;= (mneed - msum)&lt;br /&gt;
&lt;br /&gt;
zutrifft, darf der Trockner unterbrochen werden, anderenfalls darf er nicht mehr unterbrochen werden da die Restzeit evtl. nicht ausreichen könnte um den Vorgang abzuschließen. Für die Planung des Trockners wird der Consumer wie gewöhnlich nach dem Bedarf im Modul registriert. Für die Steuerung der Unterbrechbarkeit wird noch ein Code erstellt, welcher im Trockner-Device &#039;&#039;Dryerdev&#039;&#039; das Reading &#039;&#039;SF_Int&#039;&#039; zur Unterbrechnungssteuerung verwaltet. Dieses Reading wird dem Schlüssel &#039;&#039;&#039;interruptable&#039;&#039;&#039; übergeben. Für das Beispiel wird der Consumer &#039;07&#039; verwendet, es kann natürlich jede andere freie Nummer verwendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; consumer07 Dryerdev:Trockner&lt;br /&gt;
                        icon=scene_cloves_dryer type=dryer power=2000 mode=must mintime=300 &lt;br /&gt;
                        on=on off=off etotal=energy_Wh:Wh pcurr=power:W&lt;br /&gt;
                        auto=automatic asynchron=1&lt;br /&gt;
                        interruptable=Dryerdev:SF_Int:1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Kombination &#039;&#039;&#039;auto=automatic&#039;&#039;&#039; eröffnet die Möglickeit, in der Consumer-Legende den Trockner-Start zusätzlich manuell freizugeben oder zu verbieten. &lt;br /&gt;
&lt;br /&gt;
Im nachfolgenden Code werden modulinterne Subroutinen verwendet. Diese sind inklusive dem Paket &#039;&#039;FHEM::SolarForecast::&#039;&#039; anzugeben. Die erstellte Subroutine wird in die 99_mySolarForecastUtils.pm eingefügt. Die Datei 99_mySolarForecastUtils.pm wird vorher von 99_myUtils.pm kopiert und enthält für die Übersichtlichkeit nur Routinen für SolarForecast.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
############################################################################&lt;br /&gt;
#   Trocknersteuerung (einfügen in 99_mySolarForecastUtils.pm) &lt;br /&gt;
############################################################################&lt;br /&gt;
sub dryControl {&lt;br /&gt;
  my $name  = shift;&lt;br /&gt;
  my $c     = shift;                                                              # Nummer des Verbrauchers, z.B. 07&lt;br /&gt;
  my $mneed = shift;                                                              # gewöhlich benötigte Zeit für &lt;br /&gt;
                                                                                  # einen Trockengang, z.B. 120 (Minuten)&lt;br /&gt;
  &lt;br /&gt;
  $c            = sprintf &amp;quot;%02d&amp;quot;, $c;                                             # falls führende 0 vergessen wird&lt;br /&gt;
  my $dryer     = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;name&#039;, &#039;&#039;);       # Devicename des Trockners&lt;br /&gt;
  my $plstate   = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;planstate&#039;, &#039;&#039;); &lt;br /&gt;
  my $simpCstat = FHEM::SolarForecast::simplifyCstate ($plstate);                 # akt. Status des Consumers&lt;br /&gt;
&lt;br /&gt;
  if ($simpCstat =~ /started|interrupt|continu/xs) {                              # Vorgang ist gestartet&lt;br /&gt;
      my $t       = time;&lt;br /&gt;
      my $startts = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;planswitchon&#039;,  &#039;&#039;);&lt;br /&gt;
      my $stopts  = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;planswitchoff&#039;, &#039;&#039;);&lt;br /&gt;
      return if(!$startts || !$stopts);&lt;br /&gt;
      &lt;br /&gt;
      my $mrest = sprintf &#039;%.0f&#039;, (($stopts - $t) / 60);                         # Restlaufzeit (Minuten)      &lt;br /&gt;
      my $dt     = FHEM::SolarForecast::timestringsFromOffset ($name, $startts, 0);&lt;br /&gt;
      my $day    = $dt-&amp;gt;{day};&lt;br /&gt;
      my $hstart = int $dt-&amp;gt;{hour} + 1;                                          # lfd. Stunde bei Trockner-Start &lt;br /&gt;
      my $msum   = 0;&lt;br /&gt;
	  &lt;br /&gt;
      for my $hod (1..24) {                                                      # bisherige Laufzeit des Trockners&lt;br /&gt;
          next if($hod &amp;lt; $hstart);&lt;br /&gt;
          $hod = sprintf &amp;quot;%02d&amp;quot;, $hod;&lt;br /&gt;
          $msum += FHEM::SolarForecast::HistoryVal ($name, $day, $hod, &amp;quot;minutescsm${c}&amp;quot;, 0);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      my $dhash = $defs{$dryer};&lt;br /&gt;
&lt;br /&gt;
      if ($mrest &amp;gt;= ($mneed - $msum)) {&lt;br /&gt;
          readingsSingleUpdate ($dhash, &#039;SF_Int&#039;, 1, 0);                        # Interrupt-Freigabe&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
          readingsSingleUpdate ($dhash, &#039;SF_Int&#039;, 0, 0);                        # keine Interrupt-Freigabe&lt;br /&gt;
  &lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
return;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Damit die Routine mit jedem Zyklus im Modul ausgeführt wird, legen wir sie im Attribut &#039;&#039;&#039;ctrlUserExitFn&#039;&#039;&#039; an. Es werden der Name des SolarForecast-Devices, die Verbrauchernummer (07) und die gewöhnliche Laufzeit des Trockners für einen Trockenvorgang (120 Minuten) übergeben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr &amp;lt;Name&amp;gt; ctrlUserExitFn  {  &lt;br /&gt;
                               ::dryControl ($name, &#039;07&#039;, 120);&lt;br /&gt;
                            }&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Fallstudie: Umwälzpumpe Pool soll X Stunden am Tag laufen. Ist kein PV-Überschuß vorhanden, müssen die X Stunden/Tag trotzdem erreicht werden ===&lt;br /&gt;
&lt;br /&gt;
Die Vorgehensweise ähnelt der Fallstudie zuvor. Verändernd kommt hinzu, dass der Planungszeitraum bewusst sehr lang angesetzt wird mit der Option, den Zyklus des Consumers vorfristig zu beenden sobald die Laufzeit von X Stunden am Tag erreicht ist. &lt;br /&gt;
Im folgenden Beispiel soll die Pumpe 5 Stunden am Tag (300 Minuten) laufen und dabei mögliche PV-Überschüsse ausnutzen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; consumer07 Pump:Zirkulationspumpe&lt;br /&gt;
                        icon=sani_pump type=other power=50 mode=must mintime=780 notafter=09&lt;br /&gt;
                        on=on off=off etotal=energy_Wh:Wh pcurr=power:W&lt;br /&gt;
                        auto=automatic &lt;br /&gt;
                        interruptable=1 swoffcond=Pump:SF_Abort:1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit dieser Registrierung wird die Pumpe ca. 09 Uhr täglich starten. Wenn kein bzw. ungenügender PV-Überschuß vorhanden ist, erfolgt eine Unterbrechung nach dem Start. Ist genügender PV-Überschuß (wieder) vorhanden, erfolgt keine Unterbrechnung (mehr). Zusätzlich wird über den Schlüssel &#039;&#039;&#039;swoffcond&#039;&#039;&#039; eine vorfristige Beendigung veranlasst, sobald die gewünschte Tageslaufzeit erreicht ist.&lt;br /&gt;
&lt;br /&gt;
Zur Verwaltung des Schlüssels &#039;&#039;interruptable&#039;&#039; und des Readings &#039;&#039;SF_Abort&#039;&#039; verwenden wir eine leicht veränderte Subroutine aus dem vorhergehenden Fallbeispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
############################################################################&lt;br /&gt;
#   Pumpensteuerung (einfügen in 99_mySolarForecastUtils.pm) &lt;br /&gt;
############################################################################&lt;br /&gt;
sub pumpControl {&lt;br /&gt;
  my $name  = shift;&lt;br /&gt;
  my $c     = shift;                                                              # Nummer des Verbrauchers, z.B. 07&lt;br /&gt;
  my $mneed = shift;                                                              # Soll-Pumpenzeit, z.B. 300 (Minuten)&lt;br /&gt;
  &lt;br /&gt;
  $c            = sprintf &amp;quot;%02d&amp;quot;, $c;                                             # falls führende 0 vergessen wird&lt;br /&gt;
  my $pump      = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;name&#039;, &#039;&#039;);       # Devicename der Pumpe&lt;br /&gt;
  my $plstate   = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;planstate&#039;, &#039;&#039;);&lt;br /&gt;
  my $intbl     = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;interruptable&#039;, 1); &lt;br /&gt;
  my $simpCstat = FHEM::SolarForecast::simplifyCstate ($plstate);                 # akt. Status des Consumers&lt;br /&gt;
  my $dhash     = $defs{$pump};&lt;br /&gt;
&lt;br /&gt;
  readingsSingleUpdate ($dhash, &#039;SF_Abort&#039;, 0, 0);                                # default keine Zyklusbeendigung&lt;br /&gt;
&lt;br /&gt;
  if ($simpCstat =~ /started|interrupt|continu/xs) {                              # Vorgang ist gestartet&lt;br /&gt;
      my $t       = time;&lt;br /&gt;
      my $startts = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;planswitchon&#039;,  &#039;&#039;);&lt;br /&gt;
      my $stopts  = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;planswitchoff&#039;, &#039;&#039;);&lt;br /&gt;
      return if(!$startts || !$stopts);&lt;br /&gt;
      &lt;br /&gt;
      my $mrest = sprintf &#039;%.0f&#039;, (($stopts - $t) / 60);                         # Restlaufzeit (Minuten)      &lt;br /&gt;
      my $dt     = FHEM::SolarForecast::timestringsFromOffset ($name, $startts, 0);&lt;br /&gt;
      my $day    = $dt-&amp;gt;{day};&lt;br /&gt;
      my $hstart = int $dt-&amp;gt;{hour} + 1;                                          # lfd. Stunde bei Pumpen Start &lt;br /&gt;
      my $msum   = 0;&lt;br /&gt;
	  &lt;br /&gt;
      for my $hod (1..24) {                                                      # bisherige Laufzeit der Pumpe&lt;br /&gt;
          next if($hod &amp;lt; $hstart);&lt;br /&gt;
          $hod = sprintf &amp;quot;%02d&amp;quot;, $hod;&lt;br /&gt;
          $msum += FHEM::SolarForecast::HistoryVal ($name, $day, $hod, &amp;quot;minutescsm${c}&amp;quot;, 0);&lt;br /&gt;
      }&lt;br /&gt;
     &lt;br /&gt;
      if ($msum &amp;gt;= $mneed) {&lt;br /&gt;
          readingsSingleUpdate ($dhash, &#039;SF_Abort&#039;, 1, 0);                       # vorfristige Zyklusbeendigung&lt;br /&gt;
          return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ($mrest &amp;gt;= ($mneed - $msum)) {                        &lt;br /&gt;
          fhem (&amp;quot;set $name attrKeyVal consumer$c interruptable=1&amp;quot;) if(!$intbl);  # Interrupt-Freigabe&lt;br /&gt;
      }&lt;br /&gt;
      else {                        &lt;br /&gt;
          fhem (&amp;quot;set $name attrKeyVal consumer$c interruptable=0&amp;quot;) if($intbl);   # keine Interrupt-Freigabe&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
return;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Befehl &#039;&#039;attrKeyVal&#039;&#039; setzt den Schlüssel &#039;&#039;interruptable&#039;&#039; im Attribut &#039;&#039;consumer07&#039;&#039; dynamisch. Diese Strukturänderung wird automatisch im System gespeichert, sofern &#039;&#039;global-&amp;gt;autosave=1&#039;&#039; gesetzt ist. Diese Einstellung ist der FHEM default.  &lt;br /&gt;
&lt;br /&gt;
Damit die Routine mit jedem Zyklus im Modul ausgeführt wird, legen wir sie im Attribut &#039;&#039;&#039;ctrlUserExitFn&#039;&#039;&#039; an. Es werden der Name des SolarForecast-Devices, die Verbrauchernummer (07) und die Mindestlaufzeit der Umwälzpumpe (300 Minuten) übergeben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr &amp;lt;Name&amp;gt; ctrlUserExitFn  {  &lt;br /&gt;
                               ::pumpControl ($name, &#039;07&#039;, 300);&lt;br /&gt;
                            }&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dynamische Ladestromsteuerung eines Victron MultiPlus II Chargers mit Pylontech Batterie ===&lt;br /&gt;
Die nachfolgend beschriebene Lösung soll als Anregung für eigene Optimierungen verstanden werden und ist weiter ausbaufähig bzw. erweiterbar um zum Beipiel jahreszeitliche Anpassungen des Verfahrens.&lt;br /&gt;
&lt;br /&gt;
Die MultiPlus II Batteriewechselrichter von Victron sollten die Batterien nicht mit dem maximal möglichen Ladestrom beladen, da sich die Effizienz deutlich verschlechtert wenn sich die Ströme den jeweiligen Grenzwerten nähern ([https://www.victronenergy.com/upload/documents/Output-rating-operating-temperature-and-efficiency.pdf Lesestoff]). &lt;br /&gt;
Andererseits sollen die Ladeleistungen so gewählt werden, dass die verfügbare Solarenergie eine volle Aufladung der Akkus ermöglicht.&lt;br /&gt;
&lt;br /&gt;
Das Victron System ermöglicht das Auslesen und die Steuerung der Anlage via MQTT. Die Einbindung in FHEM über MQTT soll hier nicht beschrieben werden.&lt;br /&gt;
Aber wenn dies erfolgt ist, kann der Ladestrom z.B. mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
 set &amp;lt;Device&amp;gt; MaxChargeCurrent &amp;lt;Wert&amp;gt;&lt;br /&gt;
&lt;br /&gt;
eingestellt bzw. variiert werden.&lt;br /&gt;
&lt;br /&gt;
Das Modul bietet dem Nutzer die Möglichkeit in dem Attribut &#039;&#039;ctrlUserExitFn&#039;&#039; eigenen Code zur Auführung zu bringen. Der in diesem Attribut enthaltene Code wird am Ende jedes Zyklus (siehe Attribut &#039;&#039;plantControl-&amp;gt;cycleInterval&#039;&#039;) ausgeführt.&lt;br /&gt;
In dem Attribut wird dieser Code eingetragen dessen Funktion und Zusammenspiel nachfolgend erläutert wird:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{ &lt;br /&gt;
  ## Vars&lt;br /&gt;
  ########&lt;br /&gt;
  my $batdev  = (split &amp;quot; &amp;quot;, ReadingsVal ($name, &#039;currentBatteryDev&#039;, &#039;&#039;))[0];  # Batteriedevice&lt;br /&gt;
  my $vebus   = &#039;MQTT2_cerboGX_c0619ab34e08_vebus&#039;;                            # Victron Vebus Device &lt;br /&gt;
  my $mppt1   = &#039;MQTT2_cerboGX_c0619ab34e08_solarcharger_Common&#039;;              # SmartLoader Device&lt;br /&gt;
  my $maxcspc = 105;                        # max. Ladesollstrom (A) nominal&lt;br /&gt;
  my $spcorr  = 0.9;                        # Korrekturfaktor Überschuss 90%&lt;br /&gt;
  my $sch     = 0.25;                       # Verkürzungsfaktor Zeit bis Vollladung vor Sunset             &lt;br /&gt;
  &lt;br /&gt;
  my $cclvl0  = 15;                         # Ladestrom Level 0 max. 5  A (240 W) pro WR  (720  W)&lt;br /&gt;
  my $cclvl1  = 27;                         # Ladestrom Level 1 max. 9  A (432 W) pro WR  (1296 W)&lt;br /&gt;
  my $cclvl2  = 54;                         # Ladestrom Level 2 max. 18 A (864 W) pro WR  (2592 W)&lt;br /&gt;
  my $cclvl3  = 81;                         # Ladestrom Level 3 max. 27 A (1296 W) pro WR (3888 W)&lt;br /&gt;
  ###############&lt;br /&gt;
  &lt;br /&gt;
  my $cofc   = ReadingsNum ($name,  &#039;special_todayConForecastTillSunset&#039;, 0);&lt;br /&gt;
  my $pvfc   = ReadingsNum ($name,  &#039;RestOfDayPVforecast&#039;, 0);&lt;br /&gt;
  my $cpv    = ReadingsNum ($name,  &#039;Current_PV&#039;,          0);&lt;br /&gt;
  my $mppt1c = ReadingsNum ($mppt1, &#039;DC_0_Current_value&#039;,  0);             # Load I MPPT1 (max. 44 A)&lt;br /&gt;
  my $ssts   = CurrentVal  ($hash,  &#039;sunsetTodayTs&#039;,        0);&lt;br /&gt;
  my $srts   = CurrentVal  ($hash,  &#039;sunriseTodayTs&#039;,       0);&lt;br /&gt;
  my $sdiff  = ($ssts - $srts) / 3600;                                     # Sonnengang heute in h &lt;br /&gt;
  &lt;br /&gt;
  my $solh   = ReadingsNum ($name, &#039;special_SunHours_Remain&#039;, 0);          # h bis SunSet&lt;br /&gt;
  $solh      = $solh - ($sdiff * $sch);                                    # h bis SunSet - X&lt;br /&gt;
  $solh      = $solh &amp;lt; 0 ? 0 : $solh;&lt;br /&gt;
   &lt;br /&gt;
  my $ahrem  = ReadingsNum ($batdev, &#039;EnergyRemain&#039;, 0) / 48;              # Ah Bat bis SOC&lt;br /&gt;
  $ahrem     = sprintf &amp;quot;%.0f&amp;quot;, $ahrem;&lt;br /&gt;
  &lt;br /&gt;
  my $fcdiff = ($pvfc - $cofc) * $spcorr;     # Korrektur d. noch prognostizierten Überschussenergie &lt;br /&gt;
  $fcdiff    = $fcdiff &amp;lt; 0 ? 0 : $fcdiff;     # Wh&lt;br /&gt;
  &lt;br /&gt;
  my $loadcur = $maxcspc;&lt;br /&gt;
  &lt;br /&gt;
  if ($cpv &amp;amp;&amp;amp; $solh &amp;amp;&amp;amp; $ahrem &amp;amp;&amp;amp; $fcdiff &amp;gt; $ahrem) {  # Ladeanforderung und Überschuss übersteigt &lt;br /&gt;
                                                      # Lademenge&lt;br /&gt;
      my $cspc = sprintf &amp;quot;%.2f&amp;quot;, ($ahrem / $solh);    # A = Ah / h -&amp;gt; A Soll Schätzung&lt;br /&gt;
&lt;br /&gt;
      Log3 ($name, 3, qq{$name - userFn -&amp;gt; Battery charging process should be completed }.&lt;br /&gt;
                      qq{in &amp;gt;$solh&amp;lt; hours});&lt;br /&gt;
      Log3 ($name, 3, qq{$name - userFn -&amp;gt; raw Target charging current: $cspc});&lt;br /&gt;
	  &lt;br /&gt;
      $cspc = sprintf &amp;quot;%.2f&amp;quot;, ($cspc - $mppt1c);      # SmartLoader IST berücksichtigen&lt;br /&gt;
	  &lt;br /&gt;
      Log3 ($name, 3, qq{$name - userFn -&amp;gt; Charge Current minus MPPT load Current &amp;gt;$mppt1c&amp;lt;: $cspc});&lt;br /&gt;
	  &lt;br /&gt;
      $loadcur = $cspc &amp;lt;= 0       ? 0       :     # nur MPPT Ladung&lt;br /&gt;
                 $cspc &amp;lt;= $cclvl0 ? $cclvl0 :     # Übergangsbereich&lt;br /&gt;
                 $cspc &amp;lt;= $cclvl1 ? $cclvl1 :     # Ladung mit Level 1 Leistung&lt;br /&gt;
                 $cspc &amp;lt;= $cclvl2 ? $cclvl2 :     # Ladung mit Level 2 Leistung&lt;br /&gt;
                 $cspc &amp;lt;= $cclvl3 ? $cclvl3 :     # Ladung mit Level 3 Leistung&lt;br /&gt;
                 $maxcspc;                        # max. Ladesollstrom&lt;br /&gt;
	  &lt;br /&gt;
	  Log3 ($name, 3, qq{$name - userFn -&amp;gt; MaxChargeCurrent calculated: $loadcur});&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  readingsSingleUpdate ($hash, &#039;userFn_Bat_MaxChargeCurrent&#039;,       $loadcur.&#039; A&#039;,          1);&lt;br /&gt;
  readingsSingleUpdate ($hash, &#039;userFn_Bat_HoursUntilChargeFinish&#039;, sprintf (&amp;quot;%.2f&amp;quot;,$solh), 1);&lt;br /&gt;
  CommandSet           (undef, &amp;quot;$vebus MaxChargeCurrent $loadcur&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2023-05-03 201457.png|right|thumb|300px|Vorhersage PV Erzeugung und Energieverbrauch des (restlichen) Tages]]&lt;br /&gt;
Zunächst wird der am aktuellen Tag zu erwartende Totalüberschuss solarer Energie ermittelt. Das erfolgt aus der Differenz von &#039;&#039;RestOfDayPVforecast&#039;&#039; und &#039;&#039;RestOfDayConsumptionForecast&#039;&#039; unter Berücksichtigung eines Sicherheitsabschlages. Das Ergebnis liegt in Wh vor und wird bezogen auf 48 V (die Spannung des Batteriesystems) in Ah umgerechnet. &lt;br /&gt;
&lt;br /&gt;
Die noch benötigte Ladung der Batterie zur Erreichung des Soll SOC-Wertes ermittelt das ReadingsNum &#039;&#039;special_SunHours_Remain&#039;&#039; aus dem Batteriedevice, welches vom Modulreading &#039;&#039;currentBatteryDev&#039;&#039; ausgelesen wird.&lt;br /&gt;
&lt;br /&gt;
Sofern der so ermittelte solare Überschuss des (Rest)Tages die benötigte Lademenge der Batterie übersteigt, wird der DC Ladestrom so verringert, dass er sich in einem effizienten Bereich des MultiPlus II bewegt und dennoch rechnerisch ausreicht auf den Soll SOC-Wert zu laden.  &lt;br /&gt;
&lt;br /&gt;
Zu diesem Zweck wird im Modul über die Auswahl von &#039;&#039;SunHours_Remain&#039;&#039; im Attribut &#039;&#039;ctrlStatisticReadings&#039;&#039; das zusätzliche Reading &#039;&#039;special_SunHours_Remain&#039;&#039; erzeugt. Aus dem (noch) erforderlichen Ladungswert &#039;&#039;&#039;EnergyRemain&#039;&#039;&#039; (Ah) und der um eine Sicherheitszeit (&#039;&#039;Verkürzungsfaktor Zeit bis Vollladung vor Sunset&#039;&#039;) reduzierte Zeit bis zum Sonnenuntergang wird die rechnerisch erforderliche mindest Ladestromstärke ermittelt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dieser Wert wird auf die zu Anfang des Codeblocks definierten Ladelevel (&#039;&#039;Ladestrom Level X&#039;&#039;) abstrahiert und ein passender &#039;&#039;&#039;effizienter&#039;&#039;&#039; Ladestrom-Bereich ausgewählt.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2023-05-03 201719.png|right|thumb|300px|Vorhersage PV Erzeugung und Energieverbrauch des (restlichen) Tages]]&lt;br /&gt;
&lt;br /&gt;
In allen anderen Fällen, wenn z.B. rechnerisch nicht genügend oder keine Solarenergie erzeugt wird (Nachts) oder der Speicher gefüllt ist, wird der maximale (Sollwert) des Ladestroms &#039;&#039;$maxcspc = 35&#039;&#039; eingestellt. Dieser Wert entspricht dem maximalen Ladestrom gemäß Herstellerunterlagen Pylontech.&lt;br /&gt;
&lt;br /&gt;
Die Einstellung erfolgt per Set-Kommando im Victron vebus MQTT Device &#039;&#039;MQTT2_cerboGX_c0619ab34e08_vebus&#039;&#039;. Dieses Device wurde auch während der MQTT Intergration des Victron Systems angelegt und wird hier nicht näher diskutiert.&lt;br /&gt;
Zur Kontrolle des kalkulierten Wertes werden noch die Readings &#039;&#039;SolCast_userFn_MaxChargeCurrent&#039;&#039; im Batteriedevice und &#039;&#039;userFn_Bat_MaxChargeCurrent&#039;&#039; im SolarForecast Device generiert.&lt;br /&gt;
&lt;br /&gt;
Neben der Effizienzoptimierung hat dieses Verfahren auch den Vorteil einer möglichst schonenden Batterieaufladung was der Lebensdauer der Komponenten zugute kommen sollte.&lt;br /&gt;
&lt;br /&gt;
=== Poolheizung in Abhängigkeit von vorhandenem Photovoltaik-Überschuss aktivieren/deaktivieren (Eigenverbrauch optimieren) ===&lt;br /&gt;
Eine (Whirl-)Poolheizung soll bei ausreichend überschüssiger Energie aus einer Photovoltaikanlage dynamisch gesteuert werden (Eigenverbrauchsoptimierung). Im folgenden Beispiel ist ein Device mit der Bezeichnung &#039;&#039;Forecast&#039;&#039; des Typs &#039;&#039;SolarForecast bereits&#039;&#039; angelegt und konfiguriert. Ein freies Consumer-Attribut &#039;&#039;consumer01&#039;&#039; wird beispielhaft wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr Forecast consumer01 MQTT2_layzspa type=other power=1950 mode=can on=&amp;quot;heater on&amp;quot; off=&amp;quot;heater off&amp;quot; pcurr=WATT interruptable=1 swstate=heaterstate:1:0 auto=Automatiksteuerung mintime=SunPath spignorecond=EVCharger22:LadungMitPVUeberschussActive:1 icon=scene_pool notbefore=8 notafter=20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Poolheizung ist innerhalb FHEM bereits im Device &#039;&#039;MQTT2_layzspa&#039;&#039; integriert und lässt sich normalerweise per FHEM-Befehl &amp;quot;set &#039;&#039;MQTT2_layzspa heater on&amp;quot;&#039;&#039; oder &#039;&#039;&amp;quot;set MQTT2_layzspa heater off&amp;quot;&#039;&#039; steuern. Entsprechend werden die Schlüssel-Wert-Paare &#039;&#039;&amp;quot;on=&amp;quot;&#039;&#039; und &#039;&#039;&amp;quot;off=&amp;quot;&#039;&#039; definiert. &lt;br /&gt;
&lt;br /&gt;
Der Stromverbrauch einer aktiven Poolheizung ist uns bekannt und wird im Schlüssel &#039;&#039;&amp;quot;power=1950&amp;quot;&#039;&#039; definiert. Die Heizfunktion soll nur bei ausreichend Überschuss aktiviert werden dürfen und muss bei Unterschreitung sofort abgeschaltet werden. Diese Eigenschaften werden über die Schlüssel &#039;&#039;&amp;quot;mode=can&amp;quot;&#039;&#039; und &#039;&#039;&amp;quot;interruptable=&amp;quot;1&amp;quot;&#039;&#039; festgelegt. Zuletzt soll grundsätzlich nur in der Zeit zwischen 08:00 Uhr bis 20:00 Uhr geheizt werden dürfen. &lt;br /&gt;
&lt;br /&gt;
Die Schlüssel &#039;&#039;&amp;quot;notbefore=8&amp;quot;&#039;&#039; und &#039;&#039;&amp;quot;notafter=20&amp;quot;&#039;&#039; legen diese Eigenschaften fest. Zur Anzeige des Schaltzustands der Heizung wurde der Schlüssel &#039;&#039;&amp;quot;swstate=heaterstate:1:0&amp;quot;&#039;&#039; hinzugefügt (Wert 1 = Heizung aktiv, Wert 0= Heizung aus). &lt;br /&gt;
&lt;br /&gt;
==== Priorisierung vor externen PV-Überschuss gesteuerten Verbrauchern ====&lt;br /&gt;
Der Schlüssel-Wert &#039;&#039;&#039;&amp;quot;spignorecond=&amp;quot;&#039;&#039;&#039; bietet optional die Möglichkeit, einen Consumer auch ohne ausreichend PV-Überschuss einzuschalten. Bei erfüllter Bedingung wird der Verbraucher entsprechend der Planung eingeschaltet auch wenn zu dem Zeitpunkt kein PV Überschuss vorliegt. Im obigen Beispiel existiert in der Haus-Elektroinstallation eine Elektroauto-Ladestation mit eigener (externer) dynamischer PV-gesteuerter Fahrzeugladung ohne Integration in &#039;&#039;SolarForecast&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
In Abhängigkeit von PV-Generatorleistung und Sonneneinstrahlung besteht manchmal eine Möglichkeit, dass der gesamte PV-Überschuss zur Fahrzeugladung genutzt wird. Das Modul SolarForecast würde entsprechend keinen (oder zu wenig) PV-Überschuss erkennen und den Consumer &#039;&#039;MQTT2_layzspa&#039;&#039; nicht aktivieren. &lt;br /&gt;
&lt;br /&gt;
Durch Verwendung von &#039;&#039;spignorecond=EVCharger22:LadungMitPVUeberschussActive:1&#039;&#039; wird die Poolheizung gegenüber der Ladestation jedoch priorisiert mit PV-Überschuss versorgt. In diesem Beispiel wird Consumer1 aktiviert, wenn die Ladestation &amp;quot;&#039;&#039;EVCharger22&#039;&#039;&amp;quot; sich im PV-Überschuss-Modus befindet &#039;&#039;&#039;und&#039;&#039;&#039; momentan ein Fahrzeug lädt. In der Folge würde der Hausstromverbrauch um ca. 1950 Watt steigen, die externe Fahrzeugladestation diese Änderung registrieren und die Fahrzeugladeleistung entsprechend verringern oder ganz abbrechen.&lt;br /&gt;
&lt;br /&gt;
=== Luftentfeuchter PV-Überschuss gesteuert mit externer Zwangs-Einschaltbedingung ===&lt;br /&gt;
Im folgenden Beispiel wird ein Luftentfeuchter normalerweise nur bei ausreichend PV-Überschuss Energie eingeschaltet (Eigenverbrauchsoptimierung), soll jedoch bei hoher Luftfeuchtigkeit zusätzlich aktiviert werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr Forecast SolarForecast ShellyPlug1 type=other power=300 mode=can on=on off=off pcurr=power:W interruptable=1 swstate=state:on:off mintime=SunPath locktime=900 notbefore=07 notafter=22 spignorecond=ESPEasy_ESP_Easy1_am2302_sensor:humidity:high icon=Ventilator_fett&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Das in FHEM bereits angelegte Device namens &#039;&#039;ShellyPlug1&#039;&#039; dient als Zwischenstecker zur Steuerung des Luftentfeuchters. Der Schlüsselwert &amp;quot;&#039;&#039;mintime=SunPath&#039;&#039;&amp;quot; definiert die zeitliche Einplanung von Sonnenauf- bis untergang. Jedoch soll das Gerät unter keinen Umständen in der Nacht eingeschaltet werden, was über die Schlüssel &#039;&#039;&amp;quot;notbefore=07&amp;quot;&#039;&#039; bzw. &#039;&#039;&amp;quot;notafter=22&amp;quot;&#039;&#039; festgelegt ist. Weiterhin wurde im Schlüssel &#039;&#039;&amp;quot;locktime=900&amp;quot;&#039;&#039; festgelegt, dass zwischen (möglichen) Ein- und Ausschaltintervallen wenigstens 15 Minuten Wartezeit vergehen soll.&lt;br /&gt;
&lt;br /&gt;
Der Schlüssel-Wert &#039;&#039;&#039;&amp;quot;spignorecond=&amp;quot;&#039;&#039;&#039; bietet optional die Möglichkeit, ein Consumer bei erfüllter Bedingung auch ohne ausreichend PV-Überschuss einzuschalten. In diesem Beispiel wird ein Raumluftsensor abgefragt. Bei Vorhandensein der Einschaltschwelle &amp;quot;high&amp;quot; aktiviert sich der Consumer zur geplanten Laufzeit zwischen 07:00 bis 22:00 Uhr solange, bis der Raumluftsensor einen abweichenden Wert meldet.&lt;br /&gt;
&lt;br /&gt;
=== PV-Vorhersage an evcc übertragen (PV-Überschussladen von E-Autos über steuerbare Wallboxen) ===&lt;br /&gt;
[https://evcc.io evcc] ist ein Energie-Management-System, mit dem u.a. Überschussladen von Elektroautos möglich ist. Hier ist beschreiben, wie die SolarForecast-Vorhersagedaten per API von evcc abgerufen werden.&lt;br /&gt;
Lege im SolarForecast-Device ein User-Reading mit dem Namen forecast_json an. Es wandelt die Forecast-Werte in JSON und ins UTC-Zeitformat um, so dass evcc die Daten einlesen kann. Der Code wird nur ausgeführt, wenn das Reading nextCycletime ein Event erzeugt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt; &lt;br /&gt;
forecast_json:nextCycletime.* {&lt;br /&gt;
    use strict;&lt;br /&gt;
    use warnings;&lt;br /&gt;
    use JSON;&lt;br /&gt;
    use DateTime;&lt;br /&gt;
    use DateTime::Format::Strptime;&lt;br /&gt;
   &lt;br /&gt;
    my $hour = 0;&lt;br /&gt;
    my $last_start_ts;    &lt;br /&gt;
    my @output;&lt;br /&gt;
    &lt;br /&gt;
    # Parser für Datum mit CET/CEST&lt;br /&gt;
    my $parser = DateTime::Format::Strptime-&amp;gt;new(&lt;br /&gt;
        pattern   =&amp;gt; &amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;,&lt;br /&gt;
        time_zone =&amp;gt; &amp;quot;Europe/Berlin&amp;quot;,&lt;br /&gt;
    );&lt;br /&gt;
    my $start_ts;&lt;br /&gt;
    &lt;br /&gt;
    # Alle NextHour-Daten durchsuchen (als Fallback zur Vermeidung einer Endlosschleife auf max. 100 Std. begrenzen)&lt;br /&gt;
    while ($hour &amp;lt; 100) {&lt;br /&gt;
        my $hour_str = sprintf(&amp;quot;NextHour%02d&amp;quot;, $hour);&lt;br /&gt;
        my $start_str = FHEM::SolarForecast::NexthoursVal(&amp;quot;$NAME&amp;quot;, $hour_str, &amp;quot;starttime&amp;quot;, &amp;quot;na&amp;quot;);&lt;br /&gt;
        my $pvfc = FHEM::SolarForecast::NexthoursVal(&amp;quot;$NAME&amp;quot;, $hour_str, &amp;quot;pvfc&amp;quot;, &amp;quot;na&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        # Schleife beenden, wenn keine Vorhersage-Werte mehr vorhanden sind&lt;br /&gt;
        last if $start_str eq &amp;quot;na&amp;quot; or $pvfc eq &amp;quot;na&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        $start_ts = $parser-&amp;gt;parse_datetime($start_str);  # Zeitzone und Sommer/Winterzeit berücksichtigen&lt;br /&gt;
&lt;br /&gt;
        # Zeit nach UTC und ISO 8601 konvertieren und Vorhersagewert ergänzen&lt;br /&gt;
        push @output, {&lt;br /&gt;
            start =&amp;gt; $start_ts-&amp;gt;set_time_zone(&amp;quot;UTC&amp;quot;)-&amp;gt;iso8601() . &amp;quot;Z&amp;quot;,&lt;br /&gt;
            end   =&amp;gt; $start_ts-&amp;gt;add(hours =&amp;gt; 1)-&amp;gt;set_time_zone(&amp;quot;UTC&amp;quot;)-&amp;gt;iso8601() . &amp;quot;Z&amp;quot;,&lt;br /&gt;
            value =&amp;gt; 0 + $pvfc,&lt;br /&gt;
        };&lt;br /&gt;
        $hour++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    # Prüfen, ob der letzte Wert 23 Uhr war -&amp;gt; zusätzliche Stunde anhängen, damit der Tag&lt;br /&gt;
    # bei evcc als vollständig angezeigt wird (siehe https://github.com/evcc-io/evcc/issues/22979)&lt;br /&gt;
    if ($start_ts-&amp;gt;hour == 23) {&lt;br /&gt;
&lt;br /&gt;
        # Zeit nach UTC und ISO 8601 konvertieren und Vorhersagewert ergänzen&lt;br /&gt;
        push @output, {&lt;br /&gt;
            start =&amp;gt; $start_ts-&amp;gt;set_time_zone(&amp;quot;UTC&amp;quot;)-&amp;gt;iso8601() . &amp;quot;Z&amp;quot;,&lt;br /&gt;
            end   =&amp;gt; $start_ts-&amp;gt;add(hours =&amp;gt; 1)-&amp;gt;set_time_zone(&amp;quot;UTC&amp;quot;)-&amp;gt;iso8601() . &amp;quot;Z&amp;quot;,&lt;br /&gt;
            value =&amp;gt; 0,&lt;br /&gt;
        };      &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    # Ausgabe als JSON&lt;br /&gt;
    my $json = JSON-&amp;gt;new-&amp;gt;utf8-&amp;gt;pretty-&amp;gt;encode(\@output);&lt;br /&gt;
    return $json;&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2025-08-04 104835.png|right|thumb|300px|Darstellung der PV-Vorhersage in evcc auf Basis der SolarForecast-Daten]]&lt;br /&gt;
&lt;br /&gt;
Soll der Code zur Erstellung des userReadings forecast_json in die 99_myUtils ausgelagert werden, erstelle die Funktion &#039;&#039;forecast_json&#039;&#039; mit ergänztem Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;	&lt;br /&gt;
  # - Perl Module laden&lt;br /&gt;
  use strict;&lt;br /&gt;
  use warnings;&lt;br /&gt;
  use JSON;&lt;br /&gt;
  use DateTime;&lt;br /&gt;
  use DateTime::Format::Strptime;&lt;br /&gt;
&lt;br /&gt;
  forecast_json {                   &amp;lt;--- ändern&lt;br /&gt;
    my $NAME = @_;                  &amp;lt;--- ergänzen&lt;br /&gt;
    my $hour = 0;&lt;br /&gt;
    my $last_start_ts;    &lt;br /&gt;
    my @output;&lt;br /&gt;
  ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;	&lt;br /&gt;
&lt;br /&gt;
Die Definition von userReadings in SolarForecast ändert sich zum Aufruf der Funktion in:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
userReadings forecast_json:nextCycletime.* { main::forecast_json($NAME) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Kommunikation läuft über den integrierten FHEM-Webserver, der die JSON-Daten aus dem Reading forecast_json veröffentlicht. Dazu wird in FHEM eine separate Webinstanz auf einem neuen Port erstellt, die ohne [[CsrfToken-HowTo|CSFR-Token]] (Achtung, Auswirkungen auf die Sicherheit beachten!) und nur von localhost aufrufbar ist (Voraussetzung: evcc läuft auf derselben Maschine wie FHEM):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Text&amp;quot;&amp;gt;&lt;br /&gt;
define WEBapi FHEMWEB 8089   ---&amp;gt;  (define WEBapi FHEMWEB IPV6:8089 global  bei Verwendung von IPV6)&lt;br /&gt;
attr WEBapi csrfToken none&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== evcc Integration ====&lt;br /&gt;
&#039;&#039;&#039;Konfiguration über die Datei evcc.yaml&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der [https://docs.evcc.io/docs/tariffs#pv-vorhersage evcc-Konfig unter tariffs] steht die Quelle für die Solar-Vorhersage. Der FHEM-Befehl {ReadingsVal(&#039;solarforecast_dev&#039;,&#039;forecast_json&#039;,&#039;[]&#039;)} wird encoded und in die uri eingetragen. Trage statt solarforecast_dev den passenden Namen deines SolarForecast-Device ein. evcc holt die Daten aus dem Reading forecast_json dann regelmäßig ab.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;yaml&amp;quot;&amp;gt;&lt;br /&gt;
solar:&lt;br /&gt;
  type: custom&lt;br /&gt;
  interval: 20m    &lt;br /&gt;
  forecast:&lt;br /&gt;
    source: http&lt;br /&gt;
    uri: http://localhost:8089/fhem?cmd=%7BReadingsVal%28%27solarforecast_dev%27%2C%27forecast_json%27%2C%27%5B%5D%27%29%7D&amp;amp;XHR=1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Konfiguration über den UI-Editor&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der aktuellen evcc-Version wird die Vorhersageintegration über den UI-Editor mit einer veränderten Syntax vorgenommen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
tariff: solar&lt;br /&gt;
forecast:&lt;br /&gt;
  source: http&lt;br /&gt;
  uri: http://localhost:8089/fhem?cmd=%7BReadingsVal%28%27solarforecast_dev%27%2C%27forecast_json%27%2C%27%5B%5D%27%29%7D&amp;amp;XHR=1&lt;br /&gt;
  jq: |&lt;br /&gt;
    map({&lt;br /&gt;
      &amp;quot;start&amp;quot;: .start,&lt;br /&gt;
      &amp;quot;end&amp;quot;: .end,&lt;br /&gt;
      &amp;quot;value&amp;quot;: .value&lt;br /&gt;
    }) | tostring&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zur Verbesserung der Sicherheit kann das neue WEBapi Device auch ein [[CsrfToken-HowTo#csrfToken festlegen|festes CSFR-Token]] verwenden. Dieses Token muss dann in der evcc-Konfiguration an die uri mittels &amp;amp;fwcsrf=&amp;lt;festes token&amp;gt; angehängt werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Poolsteuerung inkl. Eigenverbrauchsoptimierung und zusätzlichem Verbraucher, um Einspeiselimit zu vermeiden + manuelle Steuerung durch Sonderprogramme ===&lt;br /&gt;
&#039;&#039;&#039;Vorhandene Hardware:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Poolpumpe, die über mehrere Stufen verfügt. Hier werden zwei verwendet.&lt;br /&gt;
** Pump Low: Energiesparprogramm um den Pool umzuwälzen, auch wenn nicht genug PV Leistung zur Verfügung steht. -&amp;gt; ca. 250W&lt;br /&gt;
** Pump High: Normalbetrieb wenn genug PV Überschuss zur Verfügung steht. -&amp;gt; ca. 800W zusätzlich&lt;br /&gt;
* Poolheizung: Wärmepumpe -&amp;gt; ca. 1,5kW elektrisch&lt;br /&gt;
* Nachbars Pool: Pumpe + Salzanlage +pH-Regler -&amp;gt; ca. 650W&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Anforderungen:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Pool muss täglich mindestens 1x umgewälzt werden.&lt;br /&gt;
* Im Idealfall wird der Pool &amp;gt; 2x umgewälzt.&lt;br /&gt;
* Bei genügend Überschuss soll der Pool geheizt werden. Es soll nur Sonnenstrom für die Poolheizung verwendet werden.&lt;br /&gt;
* Um das Einspeiselimit zu vermeiden, soll auch geheizt werden, wenn der Pool schon warm genug ist. (&amp;gt;28,5 °C)&lt;br /&gt;
* Sollte trotzdem noch das Einspeiselimit erreicht werden, soll auch der Pool des Nachbarn versorgt werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Herausforderungen:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Verbraucher dürfen nur in einer gewissen Reihenfolge geschaltet werden, auch wenn der Überschuss eine andere Reihenfolge ergeben würde.&lt;br /&gt;
* Pumpe mit mehreren Stufen muss als zwei Consumer abgebildet werden, um die Schaltlogik in SolarForecast abzubilden. Würde die Trennung außerhalb von Solarforecast realisiert, könnte Solarforecast den Verbraucher schlechter &amp;quot;lernen&amp;quot;, denn dann wäre es ein Consumer mit ständig wechselndem Verbrauch.&lt;br /&gt;
* Pool des Nachbarn darf nicht laut der benötigten Leistung geschaltet werden, sondern in Abhängigkeit der Einspeisebegrenzung.&lt;br /&gt;
&lt;br /&gt;
In diesem Solarforcast-Device sind 16 Verbraucher definiert. Im Weiteren werden jedoch nur die verwendeten betrachtet. Da diese Reglung mittlerweile recht komplex ist, werden auch viele Dinge, die nicht SolarForcast betreffen, aber trotzdem dazu gehören, gezeigt. Es trägt zum Verständnis bei und man kann sich hier sicher Ideen holen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ergebnis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In den folgenden beiden Bildern sieht man das Regelverhalten recht gut.&lt;br /&gt;
[[Datei:Mustertag ohne Wolken.jpg|zentriert|mini|823x823px|Wolkenloser Tag]]&lt;br /&gt;
Hier erkennt man gut das Einschalten der jeweiligen Verbraucher (Pump Low, Pump High, Wärmepumpe und Nachbar Pool). Die Wärempumpe schaltet erst bei 5kW Überschuss ein, da der Pool eigentlich schon warm genug ist. Sie dient &amp;quot;nur&amp;quot; dazu, das EInspeiselimit zu verhindern.Auch das Auschalten ist wieder deutlich zu erkennen. Die Regleung folgt dem Überschuss recht gut. (Die Leistungsspitzen auf dem Plateau sind normale Großverbraucher im Haus.)&lt;br /&gt;
[[Datei:Wechselhaft.jpg|zentriert|mini|818x818px|Wechselhafter Tag.]]&lt;br /&gt;
In diesem Bild sieht man das &amp;quot;verzweifelte&amp;quot; Regeln um das wechselhafte Wetter auszugleichen. Hier gibt es keine korrekte Reaktion und es wird durch die Sperrzeiten und andere Delays versucht, ein zu häufiges hin- und herschalten möglichst zu vermeiden. In Summe aber auch bei so einem Wetter ein akzeptables Verhalten.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Definition der Consumer:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allgemeine Erklärungen zu den Definitionen:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;asynchron=0&#039;&#039;&#039;: Da hier die Werte des Überschusses für das Timing der Schaltvorgänge verwendet werden, darf hier keine Eventsteuerung verwendet werden. Sonst kann man nicht mehr sagen, über welchen Zeitraum der Mittelwert oder der Median gebildet wurde. Dafür wurde die Zykluszeit des SolarForecast-Device auf 60 Sekunden geändert, um die Überlegungen zu vereinfachen. Bei Event-Steuerung könnte man nicht sagen ob die letzten 10 Events in den letzten 5 Sekunden oder in den letzten 10 Minuten aufgetreten sind.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;power=xxx&#039;&#039;&#039;: Wurde teilweise etwas höher als der tatsächliche Wert gewählt, um nach dem Einschalten sicherzustellen, dass nicht sofort der gesamte Überschuss &amp;quot;verbraucht&amp;quot; wird und somit gleich wieder abgeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;auto=xxx&#039;&#039;&#039;: Jeder Verbraucher benötigt sein eigenes auto-Reading, da die Automatik für die Regelung in verschiedenen Stufen ein- und ausgeschaltet werden muss.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dum_valve&#039;&#039;&#039;: Dummy-Device in dem die Zustände der Regelung abgebildet werden. Notifys lesen bzw. befüllen diesen Dummy und steuern dann die Hardware bzw. wird der Dummy durch Werte aus der Hardware passend befüllt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;surpmeth=median_xx:&#039;&#039;&#039; Durch das asynchron=0 in allen Consumern und beim Generator wird von Solarforcast genau alle 60 Sekunden ein Zyklus ausgeführt. Das führt dazu, dass der Median genau über xx Minuten gebildet wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;locktime=xx:xx&#039;&#039;&#039;: Sicherheitsvorkehrung, dass nicht zu oft geschaltet werden kann. Schont die Hardware und verhindert ein Schwingen. Abhänging vom geschalteten Gerät. z.B. soll die Wärmepumpe möglichst wenig takten, um die Lebensdauer zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Es gibt dann auch noch einige weitere Sicherheitsvorkehrungen, um diese Regelung möglichst stabil und hardwareschonend zu gestalten. Die Schwierigkeit sind nicht die Bilderbuchtage mit einem glatten Verlauf der PV-Leistung, sondern Tage mit ständig wechselndem Überschuss in der Nähe der Schaltgrenzen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;swoncond= dum_valve:sf_true:{main::xxx_On}:&#039;&#039;&#039; Hier werden verschiedene Zustände geprüft, um ein Gerät nur dann einzuschalten, wenn es sinnvoll und sicher ist.&lt;br /&gt;
&lt;br /&gt;
Details unter &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;swoffcond= dum_valve:sf_true:{main::xxx_Off}&#039;&#039;&#039;: Hier werden verschiedene Zustände geprüft, um ein Gerät nur dann auszuschalten, wenn es sinnvoll und sicher ist.&lt;br /&gt;
&lt;br /&gt;
Details unter &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pump Low: (consumer01)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
dum_valve:Pool+Low&lt;br /&gt;
aliasshort=Low&lt;br /&gt;
asynchron=0&lt;br /&gt;
auto=pump_low_auto&lt;br /&gt;
icon=scene_pool&lt;br /&gt;
interruptable=0&lt;br /&gt;
mintime=SunPath:0:180&lt;br /&gt;
mode=must&lt;br /&gt;
noshow=0&lt;br /&gt;
notafter=08:00&lt;br /&gt;
off=&amp;quot;pump_low off&amp;quot;&lt;br /&gt;
on=&amp;quot;pump_low on&amp;quot;&lt;br /&gt;
pcurr=pump_low_power&lt;br /&gt;
power=250&lt;br /&gt;
surpmeth=median_13&lt;br /&gt;
switchdev=dum_valve&lt;br /&gt;
swoffcond=dum_valve:sf_true:{main::Check_Pump_Low_Off}&lt;br /&gt;
swoncond=dum_valve:sf_true:{main::Check_Pump_Low_On}&lt;br /&gt;
swstate=pump_low:on:off&lt;br /&gt;
type=other&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterungen:&lt;br /&gt;
&lt;br /&gt;
* Die Pumpe soll ab Sonnenaufgang, bis 180 Minuten nach Sonnenuntergang (mintime=SunPath:0:180), bei mindestens 250W Überschuss (power=250) gestartet werden.&lt;br /&gt;
* Die Pumpe muss spätestens um 8:00 eingeplant werden (notafter=08:00), um das Umwälzen auch bei Schlechtwetter zu garantieren.&lt;br /&gt;
* Die Pumpe muss gestartet werden (mode=must) sobald sie eingeplant ist.&lt;br /&gt;
* swoncond sorgt dafür, dass sie vor 8:00 nur bei genügend Überschuss gestartet wird, oder es 8:00 ist. swondcond ist mit der eigentlichen Einschaltbedingung (eingeplant und mode=must) UND verknüpft. -&amp;gt; siehe &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039;&lt;br /&gt;
* Überschuss wird auch in swoncond mit der gewählten Methode geprüft.&lt;br /&gt;
* Die Pumpe darf, wenn sie gestartet wurde, auch bei fehlendem Überschuss nicht mehr unterbrochen werden. (interruptable=0)&lt;br /&gt;
* Die Pumpe wird am Ende der Einplanung ausgeschaltet oder wenn swoffcond erfüllt ist. swoffcond wird true, wenn eine gewisse Wassermenge umgewälzt wurde oder die Sicherheitsbedingungen nicht (mehr) erfüllt sind. swoffcond ist mit der eigentlichen Ausschaltbedingung (Planung endet) ODER verknüpft. -&amp;gt; siehe &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039;&lt;br /&gt;
* {&#039;&#039;&#039;main::&#039;&#039;&#039;xxx} dient dazu, um die Funktion xxx in der 99_mySolarForecastUtils.pm aus Solarforecast erreichbar zu machen.&lt;br /&gt;
* dum_valve:sf_true ist ein Reading, das fix 1 ist und als Vergleichswert für den in Klammern folgenden Perlcode dient. Wenn dieses Reading und der Perlcode gleich sind (1==1), ist die swoncond bzw swoffcond erfüllt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pump High: (consumer03)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
dum_valve:Pool+High&lt;br /&gt;
aliasshort=High&lt;br /&gt;
type=other power=1000 asynchron=0&lt;br /&gt;
auto=pump_high_auto&lt;br /&gt;
icon=scene_pool&lt;br /&gt;
pcurr=pump_high_power&lt;br /&gt;
switchdev=dum_valve&lt;br /&gt;
swstate=pump_high:on:off&lt;br /&gt;
mode=can&lt;br /&gt;
mintime=SunPath&lt;br /&gt;
on=&amp;quot;pump_high on&amp;quot;&lt;br /&gt;
off=&amp;quot;pump_high off&amp;quot;&lt;br /&gt;
surpmeth=median_5&lt;br /&gt;
noshow=0&lt;br /&gt;
locktime=180:300&lt;br /&gt;
interruptable=1&lt;br /&gt;
swoncond=dum_valve:sf_true:{main::Check_Pump_High_On}&lt;br /&gt;
swoffcond=dum_valve:sf_true:{main::Check_Pump_High_Off}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterungen:&lt;br /&gt;
&lt;br /&gt;
* Pump HIgh ist die selbe Pumpe, aber eine höhere Durchflussmenge&lt;br /&gt;
* Der Mehrverbrauch beträgt eigentlich 800W wird hier aber mit 1000W angegeben, um eine Hysterese von ca. 200W zu erreichen und damit ein schnelles Abschalten nach dem Einschalten zu verhindern.&lt;br /&gt;
* Diese Stufe wird nur bei genügend Überschuss aktiviert. (mode=can)&lt;br /&gt;
* Diese Stufe wird bei fehlendem Überschuss unterbrochen. (interruptable=1)&lt;br /&gt;
* Diese Stufe wird nur während Sonnenschein eingeplant. (mintime=SunPath)&lt;br /&gt;
* locktime sorgt dafür, dass bei schnell wechselnden Bedingungen, nicht ständig umgeschaltet wird. -&amp;gt; Schonung der Pumpe.&lt;br /&gt;
* swoncond und swoffcond -&amp;gt; siehe &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Heatpump: (consumer05)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
Pool_Strom_Heizung:Poolheizung&lt;br /&gt;
aliasshort=WP&lt;br /&gt;
type=other power=1800 asynchron=0&lt;br /&gt;
icon=sani_heating_heatpump&lt;br /&gt;
auto=heatpump_auto&lt;br /&gt;
pcurr=Pool_Pin32_monotonic_count_PowerCurrent:W&lt;br /&gt;
etotal=Pool_Pin32_monotonic_count_EnergyMeter:kWh&lt;br /&gt;
switchdev=dum_valve&lt;br /&gt;
swstate=heatpump:on:off&lt;br /&gt;
mode=can&lt;br /&gt;
locktime=600:600&lt;br /&gt;
mintime=SunPath&lt;br /&gt;
on=&amp;quot;heatpump on&amp;quot;&lt;br /&gt;
off=&amp;quot;heatpump off&amp;quot;&lt;br /&gt;
surpmeth=median_13&lt;br /&gt;
noshow=0&lt;br /&gt;
swoncond=dum_valve:sf_true:{main::CheckWPOn}&lt;br /&gt;
interruptable=1&lt;br /&gt;
swoffcond=dum_valve:sf_true:{main::CheckWPOff}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterungen:&lt;br /&gt;
&lt;br /&gt;
* Der Verbrauch ist hier wieder etwas zu hoch angegeben (1800W statt realen 1500W), um eine Hysterese zu erreichen.&lt;br /&gt;
* Da es sich hier um eine Wärmepumpe handelt, die nicht getaktet werden sollte, ist die locktime in beide Schaltrichtungen mit 10 Minuten relativ hoch.&lt;br /&gt;
* Die Ermittlung des Medians ist mit 13 Minuten recht lang, um den Überschuss über lange Zeit zu glätten, damit möglichst selten geschaltet wird. Diese 13 Minuten in Kombination mit der Locktime und der Hysterese führten bei dieser Anlage bisher dazu, dass höchstens 5 Zyklen am Tag geschaltet wurden. -&amp;gt; Hier kann das individuelle Schaltverhalten optimiert werden. Besseres Verfolgen des Überschusses vs. weniger Taktungen der Wärmepumpe.&lt;br /&gt;
* swoncond und swoffcond -&amp;gt; siehe &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nachbars Pool: (consumer07)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
Shelly_Plug_S_1:Kurz+Pool&lt;br /&gt;
aliasshort=Kurz&lt;br /&gt;
type=other power=650 asynchron=0&lt;br /&gt;
icon=scene_pool&lt;br /&gt;
auto=pool_kurz_auto&lt;br /&gt;
pcurr=power:W&lt;br /&gt;
switchdev=dum_valve&lt;br /&gt;
swstate=pool_kurz:on:off&lt;br /&gt;
mode=can&lt;br /&gt;
mintime=SunPath&lt;br /&gt;
on=&amp;quot;pool_kurz on&amp;quot;&lt;br /&gt;
off=&amp;quot;pool_kurz off&amp;quot;&lt;br /&gt;
surpmeth=median_13&lt;br /&gt;
noshow=0&lt;br /&gt;
interruptable=1&lt;br /&gt;
locktime=600:300&lt;br /&gt;
swoncond=dum_valve:sf_true:{main::Check_Pool_Kurz_On}&lt;br /&gt;
swoffcond=dum_valve:sf_true:{main::Check_Pool_Kurz_Off}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterungen:&lt;br /&gt;
&lt;br /&gt;
* Dieser Consumer dient als Einspeisebegrenzungsschutz und wird aktiviert, sobald sich der Überschuss der Einspeisegrenze nähert.  -&amp;gt; siehe &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039;&lt;br /&gt;
* Verbraucher kann recht träge geschaltet werden. (surpmeth=median_13 und locktime=600:300)&lt;br /&gt;
* Consumer wird ausgeschaltet wenn ein gewisser Überschuss unterschritten wird und somit die Einspeisegrenze wieder weit genug weg ist. -&amp;gt; siehe &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039; &lt;br /&gt;
&#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Hier sind die Funktionen, die für diese Regelung verwendet werden, der Übersichtlichkeit halber in einzelnen Blöcken mit Erklärungen dargestellt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
package main;&lt;br /&gt;
use strict;&lt;br /&gt;
use warnings;&lt;br /&gt;
&lt;br /&gt;
my $pool_dummy = &#039;dum_valve&#039;;&lt;br /&gt;
my $pool_temperature = &#039;Pool_Temp&#039;;&lt;br /&gt;
my $flow_sensor = &#039;Pool_Pin_A0&#039;;&lt;br /&gt;
my $water_counter_l1 = &#039;pump_l1_hc&#039;;&lt;br /&gt;
my $water_counter_l2 = &#039;pump_l2_hc&#039;;&lt;br /&gt;
my $target_temp = 28.4; # maximum temperature for heating, without infeed limit&lt;br /&gt;
my $pool_kurz_sw_hofb = &#039;PwSw_Schalter&#039;; # Homematic switch at pool neighbour&lt;br /&gt;
my $pool_kurz_sw_kurz = &#039;Shelly_Plug_S_1&#039;; # Shelly switch for pool Kurz at home&lt;br /&gt;
&lt;br /&gt;
my $pump_low_id			= sprintf &amp;quot;%02d&amp;quot;, 1;&lt;br /&gt;
my $pump_high_id		= sprintf &amp;quot;%02d&amp;quot;, 3;&lt;br /&gt;
my $heatpump_id			= sprintf &amp;quot;%02d&amp;quot;, 5;&lt;br /&gt;
my $pool_kurz_id		= sprintf &amp;quot;%02d&amp;quot;, 7;&lt;br /&gt;
&lt;br /&gt;
my $switch_delay = 160; # just under three minutes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub&lt;br /&gt;
SolarForecastUtils_Initialize($$)&lt;br /&gt;
{&lt;br /&gt;
  my ($hash) = @_;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Hier werden die IDs der Geräte definiert, um über sprechende Namen darauf zugreifen zu können.&lt;br /&gt;
* Einige Devices und Parameter, die immer wieder gebraucht werden sind hier angegeben.&lt;br /&gt;
* sprintf wird verwendet um sicherzustellen, dass die IDs zweistellig sind. z.B. 3 -&amp;gt; 03&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pump Low&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
###################&lt;br /&gt;
### Pumpe - LOW ###&lt;br /&gt;
###################&lt;br /&gt;
&lt;br /&gt;
sub&lt;br /&gt;
Check_Pump_Low_On{&lt;br /&gt;
my $name = &#039;energy_mgmt&#039;;&lt;br /&gt;
my $surplus	= FHEM::SolarForecast::ConsumerVal ($name,$pump_low_id,&#039;surpmethResult&#039;,&#039;&#039;);&lt;br /&gt;
my $nom_power	= FHEM::SolarForecast::ConsumerVal ($name,$pump_low_id,&#039;power&#039;,&#039;&#039;);&lt;br /&gt;
my ($min, $hour) = (localtime())[1,2];&lt;br /&gt;
my $timer = 0;&lt;br /&gt;
if($hour &amp;gt; 8 || ($hour == 8 &amp;amp;&amp;amp; $min &amp;gt;= 0)){$timer=1;}&lt;br /&gt;
&lt;br /&gt;
if(ReadingsVal($pool_dummy,&amp;quot;valve_position&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;normal&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&amp;quot;special_function&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;none&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; ($surplus &amp;gt; $nom_power&lt;br /&gt;
		|| $timer&lt;br /&gt;
	)&lt;br /&gt;
)&lt;br /&gt;
	{&lt;br /&gt;
	return 1;}&lt;br /&gt;
else&lt;br /&gt;
	{&lt;br /&gt;
	return 0;}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub&lt;br /&gt;
Check_Pump_Low_Off{&lt;br /&gt;
my $bath_mode = ReadingsVal($pool_dummy,&amp;quot;bath_mode&amp;quot;,0);&lt;br /&gt;
my $m3_l1 = ReadingsVal($water_counter_l1,&amp;quot;waterAmount&amp;quot;,0);&lt;br /&gt;
my $m3_l2 = ReadingsVal($water_counter_l2,&amp;quot;waterAmount&amp;quot;,0);&lt;br /&gt;
my $water_volume = AttrVal($pool_dummy,&amp;quot;water_volume&amp;quot;,42); #42m³&lt;br /&gt;
my $desired_cf_l1 = AttrVal($pool_dummy,&amp;quot;desired_cf_l1&amp;quot;,0); #circulation_factor_level1&lt;br /&gt;
my $desired_cf_l2 = AttrVal($pool_dummy,&amp;quot;desired_cf_l2&amp;quot;,0); #circulation_factor_level2&lt;br /&gt;
my $bathmode_factor = AttrVal($pool_dummy,&amp;quot;bathmode_factor&amp;quot;,1);&lt;br /&gt;
my $desired_amount_l1;&lt;br /&gt;
my $desired_amount_l2;&lt;br /&gt;
my $amount = $m3_l1 + $m3_l2;&lt;br /&gt;
if($bath_mode == 1){&lt;br /&gt;
	$desired_amount_l1 = $desired_cf_l1 * $water_volume;&lt;br /&gt;
	$desired_amount_l2 = $desired_cf_l2 * $water_volume;&lt;br /&gt;
}else{&lt;br /&gt;
	$desired_amount_l1 = $desired_cf_l1 * $water_volume/$bathmode_factor;&lt;br /&gt;
	$desired_amount_l2 = $desired_cf_l2 * $water_volume/$bathmode_factor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if(($amount &amp;gt; $desired_amount_l1)&lt;br /&gt;
	&amp;amp;&amp;amp; (ReadingsVal($pool_dummy,&amp;quot;pump_high&amp;quot;,&amp;quot;on&amp;quot;) eq &amp;quot;off&amp;quot;  &amp;amp;&amp;amp; ReadingsAge($pool_dummy,&amp;quot;pump_high&amp;quot;,0) &amp;gt;160)&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&amp;quot;special_function&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;none&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&amp;quot;valve_position&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;normal&amp;quot;&lt;br /&gt;
)&lt;br /&gt;
	{&lt;br /&gt;
		return 1;&lt;br /&gt;
	}else{&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Einschalten:&lt;br /&gt;
&lt;br /&gt;
* Es wird der errechnete Wert für den Überschuss von SolarForecast verwendet und auch der benötigte Überschuss aus dem Consumer ausgelesen.&lt;br /&gt;
* Das Einschalten wird erst durch erfolgreiche Prüfung der Hardwarevoraussetzungen erlaubt. -&amp;gt; Das Motorventil steht richtig und es ist kein Sonderbetrieb (Reinigung, Massage, Winter, o.ä.) aktiv.&lt;br /&gt;
* Es muss entweder genügend Überschuss vorhanden sein oder es ist 8:00.&lt;br /&gt;
&lt;br /&gt;
Ausschalten:&lt;br /&gt;
&lt;br /&gt;
* Wenn der Badebetrieb aktiv ist (bath_mode==1, [bei Außentemperatur &amp;gt; 24°C]) wird nach 90m³ Gesamtumwälzung ausgeschaltet.&lt;br /&gt;
* Wenn der Badebetrieb nicht aktiv ist (bath_mode==0, [bei Außentemperatur &amp;lt; 20°C]) wird bereits nach 42m³ Gesamtumwälzung ausgeschaltet.&lt;br /&gt;
* Prüfung, ob Pump High schon aus ist. Sollte durch die Logik gar nicht möglich sein, aber es könnte manuell oder durch einen (Logik-)Fehler trotzdem eingeschaltet sein.&lt;br /&gt;
* Prüfung, ob alle Hardware-Funktionen in einem für die Automatik geeigneten Zustand sind.&lt;br /&gt;
* Es wird auch geprüft, ob Pump High seit mindestens 3 Minuten aus ist, um zu verhindern, dass wegen fehlendem Überschuss gleich mehrere Geräte ausgeschaltet werden.&lt;br /&gt;
* Da die Zykluszeit 60 Sekunden ist, führen die 160 Sekunden dazu, dass nach drei Minuten(180 Sekunden) ein definierter Wert gilt. Mit 180 Sekunden könnte es manchaml eine Minute mehr sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pump High&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
####################&lt;br /&gt;
### Pumpe - HIGH ###&lt;br /&gt;
####################&lt;br /&gt;
&lt;br /&gt;
sub&lt;br /&gt;
Check_Pump_High_On{&lt;br /&gt;
my $bath_mode = ReadingsVal($pool_dummy,&amp;quot;bath_mode&amp;quot;,0);&lt;br /&gt;
my $m3_l1 = ReadingsVal($water_counter_l1,&amp;quot;waterAmount&amp;quot;,0);&lt;br /&gt;
my $m3_l2 = ReadingsVal($water_counter_l2,&amp;quot;waterAmount&amp;quot;,0);&lt;br /&gt;
my $water_volume = AttrVal($pool_dummy,&amp;quot;water_volume&amp;quot;,42); #42m³&lt;br /&gt;
my $desired_cf_l1 = AttrVal($pool_dummy,&amp;quot;desired_cf_l1&amp;quot;,0); #circulation_factor_level1&lt;br /&gt;
my $desired_cf_l2 = AttrVal($pool_dummy,&amp;quot;desired_cf_l2&amp;quot;,0); #circulation_factor_level2&lt;br /&gt;
my $bathmode_factor = AttrVal($pool_dummy,&amp;quot;bathmode_factor&amp;quot;,1);&lt;br /&gt;
my $desired_amount_l1;&lt;br /&gt;
my $desired_amount_l2;&lt;br /&gt;
my $amount = $m3_l1 + $m3_l2;&lt;br /&gt;
if($bath_mode == 1){&lt;br /&gt;
	$desired_amount_l1 = $desired_cf_l1 * $water_volume;&lt;br /&gt;
	$desired_amount_l2 = $desired_cf_l2 * $water_volume;&lt;br /&gt;
}else{&lt;br /&gt;
	$desired_amount_l1 = $desired_cf_l1 * $water_volume/$bathmode_factor;&lt;br /&gt;
	$desired_amount_l2 = $desired_cf_l2 * $water_volume/$bathmode_factor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if(($amount &amp;lt; $desired_amount_l2)&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&amp;quot;special_function&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;none&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&amp;quot;valve_position&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;normal&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; (ReadingsVal($pool_dummy,&amp;quot;pump_low&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot;  &amp;amp;&amp;amp; ReadingsAge($pool_dummy,&amp;quot;pump_low&amp;quot;,0) &amp;gt; $switch_delay)&lt;br /&gt;
)&lt;br /&gt;
	{return 1}&lt;br /&gt;
else&lt;br /&gt;
	{return 0}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub&lt;br /&gt;
Check_Pump_High_Off{&lt;br /&gt;
my $bath_mode = ReadingsVal($pool_dummy,&amp;quot;bath_mode&amp;quot;,0);&lt;br /&gt;
my $m3_l1 = ReadingsVal($water_counter_l1,&amp;quot;waterAmount&amp;quot;,0);&lt;br /&gt;
my $m3_l2 = ReadingsVal($water_counter_l2,&amp;quot;waterAmount&amp;quot;,0);&lt;br /&gt;
my $water_volume = AttrVal($pool_dummy,&amp;quot;water_volume&amp;quot;,42); #42m³&lt;br /&gt;
my $desired_cf_l1 = AttrVal($pool_dummy,&amp;quot;desired_cf_l1&amp;quot;,0); #circulation_factor_level1&lt;br /&gt;
my $desired_cf_l2 = AttrVal($pool_dummy,&amp;quot;desired_cf_l2&amp;quot;,0); #circulation_factor_level2&lt;br /&gt;
my $bathmode_factor = AttrVal($pool_dummy,&amp;quot;bathmode_factor&amp;quot;,1);&lt;br /&gt;
my $desired_amount_l1;&lt;br /&gt;
my $desired_amount_l2;&lt;br /&gt;
my $amount = $m3_l1 + $m3_l2;&lt;br /&gt;
&lt;br /&gt;
if($bath_mode == 1){&lt;br /&gt;
	$desired_amount_l1 = $desired_cf_l1 * $water_volume;&lt;br /&gt;
	$desired_amount_l2 = $desired_cf_l2 * $water_volume;&lt;br /&gt;
}else{&lt;br /&gt;
	$desired_amount_l1 = $desired_cf_l1 * $water_volume/$bathmode_factor;&lt;br /&gt;
	$desired_amount_l2 = $desired_cf_l2 * $water_volume/$bathmode_factor;&lt;br /&gt;
}&lt;br /&gt;
if(($amount &amp;gt; $desired_amount_l2)&lt;br /&gt;
	&amp;amp;&amp;amp; (ReadingsVal($pool_dummy,&amp;quot;heatpump&amp;quot;,&amp;quot;on&amp;quot;) eq &amp;quot;off&amp;quot;  &amp;amp;&amp;amp; ReadingsAge($pool_dummy,&amp;quot;heatpump&amp;quot;,0) &amp;gt;160)&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&amp;quot;special_function&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;none&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&amp;quot;valve_position&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;normal&amp;quot;&lt;br /&gt;
)&lt;br /&gt;
	{return 1}&lt;br /&gt;
else&lt;br /&gt;
	{return 0}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Einschalten:&lt;br /&gt;
&lt;br /&gt;
* Prüfung, ob die gewünschte Umwälzung bezüglich des Badebetriebs noch nicht erreicht wurde.&lt;br /&gt;
* Prüfung der Hardwarevoraussetzungen.&lt;br /&gt;
* Prüfung, ob Pump Low schon seit mindestens drei Minuten aktiv ist. (sollte eigentlich immer der Fall sein, wenn die Automatik für Pump High aktiv ist)&lt;br /&gt;
&lt;br /&gt;
Ausschalten:&lt;br /&gt;
&lt;br /&gt;
* Prüfung, ob die gewünschte Umwälzung bezüglich des Badebetriebs bereits erreicht wurde.&lt;br /&gt;
* Prüfung der Hardwarevoraussetzungen.&lt;br /&gt;
* Prüfung, ob die Wärmepumpe schon seit mindestens drei Minuten aus ist. Ermöglicht drei Minuten lang, den Median für den Überschuss zu aktualisieren.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wärmepumpe&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
##################&lt;br /&gt;
### Wärempumpe ###&lt;br /&gt;
##################&lt;br /&gt;
sub&lt;br /&gt;
CheckWPOn(){&lt;br /&gt;
my $name = &#039;energy_mgmt&#039;;&lt;br /&gt;
my $surplus_on = 5000; # minimum surplus to avoid infeed limit with heatpump&lt;br /&gt;
my $surplus_restart = 3000; # minimum surplus to re-enable heatpump, when avoidung infeed limit and a big consumer turned the hp off&lt;br /&gt;
&lt;br /&gt;
my $planstate = FHEM::SolarForecast::ConsumerVal ($name,$heatpump_id,&#039;planstate&#039;,&#039;&#039;);&lt;br /&gt;
my $surplus	= FHEM::SolarForecast::ConsumerVal ($name,$heatpump_id,&#039;surpmethResult&#039;,&#039;&#039;);&lt;br /&gt;
if ($planstate =~ /^([^:]+)/) {&lt;br /&gt;
	$planstate = $1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if(ReadingsVal($flow_sensor,&amp;quot;reading&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; (ReadingsVal($pool_dummy,&amp;quot;special_function&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;none&amp;quot;&lt;br /&gt;
		|| ReadingsVal($pool_dummy,&amp;quot;special_function&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;party&amp;quot;&lt;br /&gt;
	)&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&#039;heat_protection&#039;,&#039;on&#039;) eq &amp;quot;off&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&amp;quot;valve_position&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;normal&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; (ReadingsVal($pool_dummy,&amp;quot;pump_high&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot;  &amp;amp;&amp;amp; ReadingsAge($pool_dummy,&amp;quot;pump_high&amp;quot;,0) &amp;gt; $switch_delay)&lt;br /&gt;
	&amp;amp;&amp;amp; (ReadingsVal($pool_temperature,&amp;quot;temperature&amp;quot;,30) &amp;lt; $target_temp &lt;br /&gt;
		|| (ReadingsVal($pool_temperature,&amp;quot;temperature&amp;quot;,15) &amp;gt;= $target_temp&lt;br /&gt;
			&amp;amp;&amp;amp; ( $surplus &amp;gt; $surplus_on&lt;br /&gt;
				|| (($planstate eq &amp;quot;replanned&amp;quot;) &amp;amp;&amp;amp; ($surplus &amp;gt; $surplus_restart))&lt;br /&gt;
			)&lt;br /&gt;
		)&lt;br /&gt;
	)&lt;br /&gt;
)&lt;br /&gt;
	{return 1}&lt;br /&gt;
else&lt;br /&gt;
	{return 0}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub&lt;br /&gt;
CheckWPOff{&lt;br /&gt;
my $name = &#039;energy_mgmt&#039;;&lt;br /&gt;
my $surplus_off = 1000; #minimum surplus to keep heatpump on, when avoiding infeed limit&lt;br /&gt;
&lt;br /&gt;
my $surplus	= FHEM::SolarForecast::ConsumerVal ($name,$heatpump_id,&#039;surpmethResult&#039;,&#039;&#039;);&lt;br /&gt;
if((ReadingsVal($flow_sensor,&amp;quot;reading&amp;quot;,&amp;quot;on&amp;quot;) eq &amp;quot;off&amp;quot;&lt;br /&gt;
	|| !((ReadingsVal($pool_dummy,&amp;quot;special_function&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;none&amp;quot;) &lt;br /&gt;
		|| (ReadingsVal($pool_dummy,&amp;quot;special_function&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;party&amp;quot;)&lt;br /&gt;
	)&lt;br /&gt;
	|| ReadingsVal($pool_dummy,&#039;heat_protection&#039;,&#039;off&#039;) eq &amp;quot;on&amp;quot;&lt;br /&gt;
	|| ReadingsVal($pool_dummy,&amp;quot;valve_position&amp;quot;,&amp;quot;&amp;quot;) ne &amp;quot;normal&amp;quot;&lt;br /&gt;
	|| ((ReadingsVal($pool_temperature,&amp;quot;temperature&amp;quot;,15) &amp;gt; $target_temp)&lt;br /&gt;
		&amp;amp;&amp;amp; ($surplus &amp;lt; $surplus_off)&lt;br /&gt;
		)&lt;br /&gt;
	)&lt;br /&gt;
	&amp;amp;&amp;amp; (ReadingsVal($pool_dummy,&amp;quot;heatpump&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot;  &amp;amp;&amp;amp; ReadingsAge($pool_dummy,&amp;quot;heatpump&amp;quot;,0) &amp;gt; $switch_delay)&lt;br /&gt;
)&lt;br /&gt;
	{return 1}&lt;br /&gt;
else&lt;br /&gt;
	{return 0}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Einschalten:&lt;br /&gt;
&lt;br /&gt;
* Prüfung, ob Flussensor ein. (Pool_pin_A0) -&amp;gt; Wasser fließt durch die Wärmepumpe.&lt;br /&gt;
* Prüfung, ob Pool in Normal- oder Partybetrieb ist und das Ventil in Normalposition ist. In beiden Fällen läuft Pump High.&lt;br /&gt;
* Einschalten wenn genug Überschuss da ist und die Temperatur &amp;lt;28.4°C ist oder wenn über 5000W Überschuss (Einspeisebegrenzung bei 5900W) da ist, egal wie warm der Pool ist.&lt;br /&gt;
* Sonderfall: Wenn die Wärmepumpe durch einen/mehrere Großverbrucher &amp;quot;kurz&amp;quot; ausgeschaltet wurde (swoffcond) wird sie ausgeplant. Ein Notify plant sie wieder ein. Wenn das passiert, soll die Wärmepumpe aber wieder bei 3000W Überschuss gestartet werden, um die Energie noch weiter zu nutzen bis der Überschuss unter 1000W fällt. (Hysterese von 500W, da die WP nur 1500W braucht)&lt;br /&gt;
&lt;br /&gt;
Ausschalten:&lt;br /&gt;
&lt;br /&gt;
* Ausschalten sobald hardwaremäßig irgendetwas faul ist. (Betriebsart, Ventilstellung, Durchfluss)&lt;br /&gt;
* Ausschalten wenn kein Überschuss. (interruptable=1)&lt;br /&gt;
* Wenn Wassertemperatur über 28,5°C und der Überschuss kleiner als 1000W ist.&lt;br /&gt;
* Nur schalten, wenn Wärmepumpe läuft und seit mindestens drei Minuten läuft (Sicherheit). Das verhindert das erneute Triggern des Notifys, wenn die Pumpe schon aus ist. Sollte nicht passieren, aber sicher ist sicher.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nachbar Pool&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
###################&lt;br /&gt;
### Pool - KURZ ###&lt;br /&gt;
###################&lt;br /&gt;
sub&lt;br /&gt;
Check_Pool_Kurz_On{&lt;br /&gt;
my $name = &#039;energy_mgmt&#039;;&lt;br /&gt;
my $surplus	= FHEM::SolarForecast::ConsumerVal ($name,$pool_kurz_id,&#039;surpmethResult&#039;,&#039;&#039;);&lt;br /&gt;
if(($surplus &amp;gt; 3000)&lt;br /&gt;
	&amp;amp;&amp;amp; ((ReadingsVal($pool_dummy,&amp;quot;heatpump&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot;  &amp;amp;&amp;amp; ReadingsAge($pool_dummy,&amp;quot;heatpump&amp;quot;,0) &amp;gt;160) || ReadingsVal($pool_dummy,&#039;heat_protection&#039;,&#039;off&#039;) eq &#039;on&#039; ))&lt;br /&gt;
	{return 1}&lt;br /&gt;
else&lt;br /&gt;
	{return 0}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub&lt;br /&gt;
Check_Pool_Kurz_Off{&lt;br /&gt;
my $name = &#039;energy_mgmt&#039;;&lt;br /&gt;
my $surplus	= FHEM::SolarForecast::ConsumerVal ($name,$pool_kurz_id,&#039;surpmethResult&#039;,&#039;&#039;);&lt;br /&gt;
if(($surplus &amp;lt; 1000 )&lt;br /&gt;
	&amp;amp;&amp;amp; (ReadingsVal($pool_dummy,&amp;quot;pool_kurz&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot;  &amp;amp;&amp;amp; ReadingsAge($pool_dummy,&amp;quot;pool_kurz&amp;quot;,0) &amp;gt;160))&lt;br /&gt;
	{return 1}&lt;br /&gt;
else&lt;br /&gt;
	{return 0}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Einschalten:&lt;br /&gt;
&lt;br /&gt;
* Überschuss ist nahe der Einspeisegrenze (5900W) und Wärmepumpe läuft seit mindestens drei Minuten. Es wird schon bei 3000W eingeschaltet, um dem Nachbarn etwas Gutes zu tun ;-)&lt;br /&gt;
&lt;br /&gt;
Ausschalten:&lt;br /&gt;
&lt;br /&gt;
* Überschuss ist unter 1000W. -&amp;gt; Um noch Reserven für den eigenen Verbrauch zu haben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hilfsfunktionen&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ctrlUserExitFn&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Hier erfolgt nach jedem Zyklus die Festlegung der verschiedenen Automatikmodi.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
#############################################################&lt;br /&gt;
##################### Exit Function #########################&lt;br /&gt;
#############################################################&lt;br /&gt;
my $ctrl_dummy	= &amp;quot;dum_valve&amp;quot;; # dummy device for pool-control&lt;br /&gt;
my $automatic	= ReadingsNum($ctrl_dummy,&amp;quot;sf_automatic&amp;quot;,1);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if($automatic){&lt;br /&gt;
&lt;br /&gt;
	my $pump_low_state = ReadingsVal($ctrl_dummy,&#039;pump_low&#039;,&#039;on&#039;);&lt;br /&gt;
	my $pump_low_auto	= FHEM::SolarForecast::ConsumerVal ($name, $pump_low_id, &#039;auto&#039;, &#039;&#039;);	# Automatikmodus der Pumpe&lt;br /&gt;
&lt;br /&gt;
	my $pump_high_state = ReadingsVal($ctrl_dummy,&#039;pump_high&#039;,&#039;on&#039;);&lt;br /&gt;
	my $pump_high_auto	= FHEM::SolarForecast::ConsumerVal ($name, $pump_high_id, &#039;auto&#039;, &#039;&#039;);	# Automatikmodus der Pumpe&lt;br /&gt;
&lt;br /&gt;
	my $heatpump_state = ReadingsVal($ctrl_dummy,&#039;heatpump&#039;,&#039;on&#039;);&lt;br /&gt;
	my $heatpump_auto	= FHEM::SolarForecast::ConsumerVal ($name, $heatpump_id, &#039;auto&#039;, &#039;&#039;);	# Automatikmodus der Wärmepumpe&lt;br /&gt;
	my $pool_heat_protection = ReadingsVal($ctrl_dummy,&#039;heat_protection&#039;,&#039;on&#039;);&lt;br /&gt;
&lt;br /&gt;
	my $pool_kurz_state = ReadingsVal($ctrl_dummy,&#039;pool_kurz&#039;,&#039;on&#039;);&lt;br /&gt;
	my $pool_kurz_auto	= FHEM::SolarForecast::ConsumerVal ($name, $pool_kurz_id, &#039;auto&#039;, &#039;&#039;);	# Automatikmodus des Pools&lt;br /&gt;
&lt;br /&gt;
	my $pump_low_delay	= FHEM::SolarForecast::ConsumerVal ($name, $pump_low_id, &#039;surpmeth&#039;, &#039;&#039;);&lt;br /&gt;
	if ($pump_low_delay =~ /_(\d+)/) {&lt;br /&gt;
    	$pump_low_delay = int(($1/2 + 1) * 60);&lt;br /&gt;
		Log3 (&amp;quot;SolarForecast&amp;quot;, 1, &amp;quot;SolarForecast: pump_low_delay: $pump_low_delay&amp;quot;);&lt;br /&gt;
	} else {&lt;br /&gt;
    	$pump_low_delay = 220;&lt;br /&gt;
		Log3 (&amp;quot;SolarForecast&amp;quot;, 1, &amp;quot;SolarForecast: warning - surpmeth for pump_low is: $pump_low_delay, but must be given as method_number, using fallback value&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	my $pump_high_delay	= FHEM::SolarForecast::ConsumerVal ($name, $pump_high_id, &#039;surpmeth&#039;, &#039;&#039;);&lt;br /&gt;
	if ($pump_high_delay =~ /_(\d+)/) {&lt;br /&gt;
    	$pump_high_delay = int(($1/2 + 1) * 60);&lt;br /&gt;
	} else {&lt;br /&gt;
    	$pump_high_delay = 160;&lt;br /&gt;
		Log3 (&amp;quot;SolarForecast&amp;quot;, 1, &amp;quot;SolarForecast: warning - surpmeth for pump_high is: $pump_high_delay, but must be given as method_number, using fallback value&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	my $heatpump_delay	= FHEM::SolarForecast::ConsumerVal ($name, $heatpump_id, &#039;surpmeth&#039;, &#039;&#039;);&lt;br /&gt;
	if ($heatpump_delay =~ /_(\d+)/) {&lt;br /&gt;
    	$heatpump_delay = int(($1/2 + 1) * 60);&lt;br /&gt;
	} else {&lt;br /&gt;
    	$heatpump_delay = 290;&lt;br /&gt;
		Log3 (&amp;quot;SolarForecast&amp;quot;, 1, &amp;quot;SolarForecast: warning - surpmeth for heatpump is: $heatpump_delay, but must be given as method_number, using fallback value&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	my $pool_kurz_delay	= FHEM::SolarForecast::ConsumerVal ($name, $pool_kurz_id, &#039;surpmeth&#039;, &#039;&#039;);&lt;br /&gt;
	if ($pool_kurz_delay =~ /_(\d+)/) {&lt;br /&gt;
    	$pool_kurz_delay = int(($1/2 + 1) * 60);&lt;br /&gt;
	} else {&lt;br /&gt;
    	$pool_kurz_delay = 160;&lt;br /&gt;
		Log3 (&amp;quot;SolarForecast&amp;quot;, 1, &amp;quot;SolarForecast: warning - surpmeth for pool_kurz is: $pool_kurz_delay, but must be given as method_number&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
############################&lt;br /&gt;
# Überhitzungsschutz aktiv #&lt;br /&gt;
############################&lt;br /&gt;
&lt;br /&gt;
if($pool_heat_protection eq &#039;on&#039;){&lt;br /&gt;
	if($heatpump_auto == 1){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy heatpump_auto 0&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	if($heatpump_state eq &amp;quot;on&amp;quot;){&lt;br /&gt;
			fhem(&amp;quot;set $ctrl_dummy heatpump off&amp;quot;)&lt;br /&gt;
	}&lt;br /&gt;
	#################&lt;br /&gt;
	#### on-chain ###&lt;br /&gt;
	#################&lt;br /&gt;
	if($pump_low_state eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;pump_low&#039;,0) &amp;gt; $pump_high_delay &amp;amp;&amp;amp; $pump_high_auto == 0  &amp;amp;&amp;amp; $pool_kurz_auto == 0){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pump_high_auto 1&amp;quot;);&lt;br /&gt;
	}elsif($pump_high_state eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;pump_high&#039;,0) &amp;gt; $pool_kurz_delay &amp;amp;&amp;amp; $pool_kurz_auto == 0 &amp;amp;&amp;amp; $pump_high_auto == 1){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pool_kurz_auto 1&amp;quot;);&lt;br /&gt;
	}elsif($pool_kurz_state eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; $pool_kurz_auto == 1 &amp;amp;&amp;amp; $pump_high_auto == 1){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pump_high_auto 0&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	#################&lt;br /&gt;
	### off-chain ###&lt;br /&gt;
	#################&lt;br /&gt;
	if($pool_kurz_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;pool_kurz&#039;,0) &amp;gt; $pump_high_delay &amp;amp;&amp;amp; $pool_kurz_auto == 1 &amp;amp;&amp;amp; $pump_high_auto == 0){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pump_high_auto 1&amp;quot;);&lt;br /&gt;
	}elsif($pump_high_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $pump_high_auto == 1 &amp;amp;&amp;amp; $pool_kurz_auto == 1){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pool_kurz_auto 0&amp;quot;);&lt;br /&gt;
	}elsif($pump_low_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $pump_high_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $pump_high_auto == 1 &amp;amp;&amp;amp; $pool_kurz_auto == 0){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pump_high_auto 0&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
##################################&lt;br /&gt;
# Überhitzungsschutz nicht aktiv #&lt;br /&gt;
##################################&lt;br /&gt;
}else{&lt;br /&gt;
	if($heatpump_auto == 0 &amp;amp;&amp;amp; $heatpump_state eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		if($pool_kurz_state eq &amp;quot;on&amp;quot;){&lt;br /&gt;
			fhem(&amp;quot;set $ctrl_dummy pool_kurz off&amp;quot;);&lt;br /&gt;
		}	&lt;br /&gt;
		if($pool_kurz_auto == 1){&lt;br /&gt;
			fhem(&amp;quot;set $ctrl_dummy pool_kurz_auto 0&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	#################&lt;br /&gt;
	#### on-chain ###&lt;br /&gt;
	#################&lt;br /&gt;
	if($pump_low_state eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;pump_low&#039;,0) &amp;gt; $pump_high_delay &amp;amp;&amp;amp; $pump_high_auto == 0 &amp;amp;&amp;amp; $heatpump_auto == 0 &amp;amp;&amp;amp; $pool_kurz_auto == 0){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pump_high_auto 1&amp;quot;);&lt;br /&gt;
	}elsif($pump_high_state eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;pump_high&#039;,0) &amp;gt; $heatpump_delay &amp;amp;&amp;amp; $heatpump_auto == 0 &amp;amp;&amp;amp; $pool_kurz_auto == 0 &amp;amp;&amp;amp; $pump_high_auto == 1){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy heatpump_auto 1&amp;quot;);&lt;br /&gt;
	}elsif($heatpump_state eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;heatpump&#039;,0) &amp;gt; $pool_kurz_delay &amp;amp;&amp;amp; $pump_high_state eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; $pool_kurz_auto == 0 &amp;amp;&amp;amp; $pump_high_auto == 1 &amp;amp;&amp;amp; $heatpump_auto == 1){&lt;br /&gt;
		# pump_high muss on sein, da sonst die automatik ausgeschaltet wird wenn die pumpe gerade interrupted ist.&lt;br /&gt;
		# Bei unterschiedlichen Medianlängen ist es möglich, dass WP ein ist und pump_high abschaltet wegen surplus == 0&lt;br /&gt;
		# Nachbarpool würde auf EIN warten, aber pump_high dürfte nicht wieder einschalten, obwohl genügend Überschuss da ist.&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pump_high_auto 0&amp;quot;);&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pool_kurz_auto 1&amp;quot;);&lt;br /&gt;
	}elsif($pool_kurz_state eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; $pool_kurz_auto == 1 &amp;amp;&amp;amp; $heatpump_auto == 1 &amp;amp;&amp;amp; $pump_high_auto == 0){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy heatpump_auto 0&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	#################&lt;br /&gt;
	### off-chain ###&lt;br /&gt;
	#################&lt;br /&gt;
	if($pool_kurz_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;pool_kurz&#039;,0) &amp;gt; $heatpump_delay &amp;amp;&amp;amp; $pool_kurz_auto == 1 &amp;amp;&amp;amp; $heatpump_auto == 0 &amp;amp;&amp;amp; $pump_high_auto == 0){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy heatpump_auto 1&amp;quot;);&lt;br /&gt;
	}elsif($heatpump_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;heatpump&#039;,0) &amp;gt; $pump_high_delay &amp;amp;&amp;amp; $heatpump_auto == 1 &amp;amp;&amp;amp; $pump_high_auto == 0 &amp;amp;&amp;amp; $pool_kurz_auto == 1){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pool_kurz_auto 0&amp;quot;);&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pump_high_auto 1&amp;quot;);&lt;br /&gt;
	}elsif($pump_high_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $heatpump_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $pump_high_auto == 1 &amp;amp;&amp;amp; $heatpump_auto == 1 &amp;amp;&amp;amp; $pool_kurz_auto == 0){&lt;br /&gt;
#	heatpump muss aus sein, da sonst vor Ablauf der Locktime die Automatik ausgeschaltet wird und die WP nicht mehr ausschalten kann.&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy heatpump_auto 0&amp;quot;);&lt;br /&gt;
	}elsif($pump_low_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $pump_high_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $pump_high_auto == 1 &amp;amp;&amp;amp; $heatpump_auto == 0){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pump_high_auto 0&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
#################################################&lt;br /&gt;
# Check hardware-state vs. reading-state&lt;br /&gt;
# re-trigger notify&lt;br /&gt;
#################################################&lt;br /&gt;
my $delay_retrigger = 100; #delay time to wait until re-trigger the notify&lt;br /&gt;
&lt;br /&gt;
if(ReadingsVal($ctrl_dummy,&#039;pool_kurz&#039;,&#039;on&#039;) eq &#039;off&#039; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;pool_kurz&#039;,0) &amp;gt; $delay_retrigger &amp;amp;&amp;amp; ReadingsVal($pool_kurz_sw_kurz,&#039;state&#039;,&#039;off&#039;) eq &#039;on&#039;){&lt;br /&gt;
	# re-trigger notify&lt;br /&gt;
	fhem(&amp;quot;trigger dum_valve pool_kurz: off&amp;quot;);&lt;br /&gt;
	Log3 (&amp;quot;SolarForecast&amp;quot;, 1, &amp;quot;SolarForecast: Pool-Kurz-off must be re-triggered&amp;quot;);&lt;br /&gt;
	DebianMail(&#039;mail@example.org&#039;,&#039;Notify Pool Kurz&#039;,&amp;quot;Notify hat nicht ausgeschaltet -&amp;gt; re-trigger&amp;quot;);&lt;br /&gt;
}elsif(ReadingsVal($ctrl_dummy,&#039;pool_kurz&#039;,&#039;off&#039;) eq &#039;on&#039; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;pool_kurz&#039;,0) &amp;gt; $delay_retrigger &amp;amp;&amp;amp; ReadingsVal($pool_kurz_sw_kurz,&#039;state&#039;,&#039;on&#039;) eq &#039;off&#039;){&lt;br /&gt;
	# re-trigger notify&lt;br /&gt;
	fhem(&amp;quot;trigger dum_valve pool_kurz: on&amp;quot;);&lt;br /&gt;
	Log3 (&amp;quot;SolarForecast&amp;quot;, 1, &amp;quot;SolarForecast: Pool-Kurz-on must be re-triggered&amp;quot;);&lt;br /&gt;
	DebianMail(&#039;mail@example.org&#039;,&#039;Notify Pool Kurz&#039;,&amp;quot;Notify hat nicht eingeschaltet -&amp;gt; re-trigger&amp;quot;);&lt;br /&gt;
}elsif((ReadingsVal($pool_kurz_sw_kurz,&#039;state&#039;,&#039;off&#039;) eq &#039;set_on&#039; || ReadingsVal($pool_kurz_sw_kurz,&#039;state&#039;,&#039;off&#039;) eq &#039;set_off&#039;) &amp;amp;&amp;amp; ReadingsAge($pool_kurz_sw_kurz,&#039;state&#039;,0) &amp;gt; $delay_retrigger){&lt;br /&gt;
	# state not clear&lt;br /&gt;
	Log3 (&amp;quot;SolarForecast&amp;quot;, 1, &amp;quot;SolarForecast: Pool-Kurz state unclear&amp;quot;);&lt;br /&gt;
	DebianMail(&#039;mail@example.org&#039;,&#039;Status Pool Kurz unklar&#039;,&amp;quot;Status HM-Schalter set_xx&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Erläuterungen:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Verzögerungen der einzelnen Stufen:&#039;&#039;&#039;&lt;br /&gt;
** Die delays der einzelnen Stufen werden aus den surpmethods berechnet. Das dient dazu, dass der Median mit den Werten nach dem ein-/ausschalten des vorheriegen Verbrauchers bis zur Hälfte + einen Wert gefüllt wird und somit sicher das Umschalten des vorherigen Verbrauchers den Median nicht mehr beeinflusst.&lt;br /&gt;
* &#039;&#039;&#039;Überhitzungsschutz:&#039;&#039;&#039;&lt;br /&gt;
** Da durch die Wärmepumpe Überschuss &amp;quot;verheizt&amp;quot; wird, der durch das Einspeiselimit gar nicht produziert würde, kann es vorkommen, dass der Pool unangenehm warm wird.&lt;br /&gt;
** Um das zu vermeiden gibt es ein Reading, welches gesetzt wird, wenn der Pool eine gewisse Temperatur überschreitet. Dieses Setzen und Zurücksetzen erfolgt mit einer Hysterese von 0.2°C, um ein Takten der Wärmepumpe zu verhindern. Diese 0.4°C sind bei dieser Wassermenge einige Stunden.&lt;br /&gt;
** Wenn der Überhitzungsschutz aktiv ist, wird die Wärmepumpe in der Kette übersprungen.&lt;br /&gt;
** Wenn sich der Hitzeschutz während des Betriebs ändert, wird die Wärmepumpe bzw. der Pool vom Nachbarn passend ausgeschaltet und die Modi entsprechend gesetzt.&lt;br /&gt;
* &#039;&#039;&#039;On-chain:&#039;&#039;&#039;&lt;br /&gt;
** Wenn am Morgen Pump Low seit $pump_low_delay aktiv ist und alle folgenden Consumer noch nicht, dann wird die nächste Stufe freigegeben. -&amp;gt; Pump High&lt;br /&gt;
** Wenn Pump High seit $pump_high_delay aktiv ist und alle folgenden Consumer noch nicht, wird die Wärmepumpe freigegeben. -&amp;gt; Heatpump&lt;br /&gt;
** Wenn die Wärmepumpe seit $heatpump_delay aktiv ist und der letzte Consumer noch nicht, wird der letzte Verbraucher freigegeben. -&amp;gt; Pool Kurz Gleichzeitig wird die Automatik für Pump High ausgeschaltet, da dieser Verbraucher erst unterbrochen werden darf wenn die Wärmepumpe aus ist!&lt;br /&gt;
** Wenn der letzte Verbraucher aktiviert ist, wird die Automatik der Wärmepumpe deaktiviert, da ja zuerst der letzte Verbraucher (Pool Kurz) wieder ausgeschaltet werden muss, bevor der vorletzte (Wärmepumpe) wieder ausgeschaltet werden darf. Da es keinen nachfolgenden Verbraucher mehr gibt, kann hier auf ein delay verzichtet werden, da es nicht passieren kann, dass zwei Verbraucher wegen sehr hohem Überschuss unmittelbar hintereinander geschaltet werden können.&lt;br /&gt;
[[Datei:Poolsteuerung mit unterschiedlichen Automatikmodi.jpg|alternativtext=Poolsteuerung|mini|Consumer der Poolsteuerung|500x500px]]&lt;br /&gt;
&#039;&#039;&#039;Wichtig:&#039;&#039;&#039; Es dürfen immer nur maximal zwei unterbrechbare Consumer im Automatikmodus sein. Der &amp;quot;aktuelle&amp;quot;, der ja aufgrund von fehlendem Überschuss jederzeit unterbrochen werden kann und der &amp;quot;folgende&amp;quot; Consumer, der auf das Einschalten wartet. Pump Low ist immer im Automatikmodus, da diese nie unterbrochen wird. (mode=must, interruptable=0)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Off-chain:&#039;&#039;&#039;&lt;br /&gt;
** Wenn der letzte Verbraucher seit mindestens der delay-Zeit aufgrund von fehlendem Überschuss inaktiv war, im Automatikmodus ist und der vorherige Verbraucher nicht im Automatikmodus ist, wird der vorherige Verbraucher in den Automatikmodus geschaltet und wartet jetzt auch auf das Ausschalten. Wenn der Überschuss steigt, springt man wieder in die on-chain und der letzte Verbraucher wird eingeschaltet und die Automatik des vorletzten Verbrauchers deaktiviert.&lt;br /&gt;
** Wenn die Wärmepumpe seit mindestens der delay-Zeit aus ist, sich im Automatikmodus befind und Pump High noch nicht im Automatikmodus ist, wird die Automatik für den Nachbarpool ausgeschaltet, da er ja jetzt nicht mehr einschalten darf, da zuerst die Wärmepumpe ein sein müsste. Die Automatik von Pump High wird wieder aktiviert, da diese jetzt auf das Ausschalten wartet. Steigt der Überschuss wieder, wird in den entsprechenden On-chain Zweig gesprungen.&lt;br /&gt;
** Wenn Pump High mindestens die delay-Zeit aus ist, wird die Automatik der Wärmepumpe deaktiviert, da diese ja erst einschalten darf, wenn Pump High wieder läuft. Steigender Überschuss führt wieder zum aktivieren von Pump High und zum Sprung in den entsprechenden On-chain Zweig.&lt;br /&gt;
** Wenn Pump Low ausgeschaltet wird, wird sofort die Automatik für Pump High ausgeschaltet, da durch das spätere Ausschalten von (der evtl. wieder eingeschalteten) Pump High, hardwaremäßig wieder Pump Low aktiviert wird, aber durch SolarForecast nie ausgeschaltet wird, da Pump Low vor ein paar Minuten ja schon logisch ausgeschaltet wurde.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig:&#039;&#039;&#039; Es dürfen immer nur maximal zwei unterbrechbare Consumer im Automatikmodus sein. Der &amp;quot;aktuelle&amp;quot;, der ja aufgrund von neuem Überschuss jederzeit wieder gestartet werden kann und der &amp;quot;vorherige&amp;quot; Consumer, der auf das Ausschalten wartet.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Synchronisation Hardware vs. Reading:&#039;&#039;&#039;Manchmal passiert es, dass durch die etwas aufwendigen Umschaltprozesse die Hardware dem Reading nicht folgt/folgen kann. Evtl. Gründe sind Funkunterbrechung, verzögerte Umschaltung usw. Daher wird bei jedem Zyklus der Status geprüft und evtl. das event nochmal getriggert, um die Umschaltung erneut auszuführen.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hilfs-Notifys für die Automatik&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Da durch das Verwenden von swoffcond die Verbraucher beim Ausschalten auch ausgeplant werden, aber eigentlich &amp;quot;nur&amp;quot; unterbrochen werden sollen, müssen sie wieder neu eingeplant werden. Dazu sind notifys nötig. Wichtig: IDs müssen zweistellig angegeben werden!&lt;br /&gt;
&lt;br /&gt;
Wärmepumpe:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
dum_valve:heatpump:.off sleep 10; set energy_mgmt consumerNewPlanning 05&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Nachbar Pool:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
dum_valve:pool_kurz:.off sleep 10; set energy_mgmt consumerNewPlanning 07&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Pumpe mit einem Energiezähler als zwei Consumer verwenden&#039;&#039;&#039;  &lt;br /&gt;
&lt;br /&gt;
Die verwendete Pumpe hat vier Betriebsarten mit unterschiedlichen Leistungen. Da sie als zwei Consumer abgebildet wird, führt das dazu, dass die Leistung fälschlicherweise von SolarForecast auch zweimal gezählt wird. Die Lösung sind Dummy-Readings, welche die Leistungsdaten passend auseinander rechnen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
Pool_Strom_Pumpe:Pool_Pin31_monotonic_count_PowerCurrent:.* {&lt;br /&gt;
my $power = $EVTPART1;&lt;br /&gt;
my $pump_low = ReadingsVal(&#039;dum_valve&#039;,&#039;pump_low&#039;,&#039;off&#039;);&lt;br /&gt;
my $pump_high = ReadingsVal(&#039;dum_valve&#039;,&#039;pump_high&#039;,&#039;off&#039;);&lt;br /&gt;
my $power_low_sim = 250;&lt;br /&gt;
&lt;br /&gt;
if($pump_low eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; $pump_high eq &amp;quot;on&amp;quot;){	&lt;br /&gt;
	my $power_low = $power_low_sim; #fiktiver Verbrauch der niedrigen Stufe&lt;br /&gt;
	my $power_high = $power - $power_low_sim;&lt;br /&gt;
	fhem(&amp;quot;set dum_valve pump_low_power $power_low&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set dum_valve pump_high_power $power_high&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
elsif($pump_low eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; $pump_high eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set dum_valve pump_low_power $power&amp;quot;);&lt;br /&gt;
		fhem(&amp;quot;set dum_valve pump_high_power 0&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
elsif($pump_low eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $pump_high eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set dum_valve pump_low_power 0&amp;quot;);&lt;br /&gt;
		fhem(&amp;quot;set dum_valve pump_high_power 0&amp;quot;);&lt;br /&gt;
}elsif($pump_low eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $pump_high eq &amp;quot;on&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set dum_valve pump_low_power 0&amp;quot;);&lt;br /&gt;
		fhem(&amp;quot;set dum_valve pump_high_power $power&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Erläuterungen:&lt;br /&gt;
&lt;br /&gt;
* Es sind alle vier Möglichkeiten der zwei Pumpenlevel abgebildet.&lt;br /&gt;
* Wenn die Automatik deaktiviert ist und die Level 1-4 von extern geschaltet werden, zählen sie dadurch korrekterweise nicht zu diesen beiden Consumern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Notifys für das hardwaremäßige Schalten der Consumer&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Es werden einige Notifys verwendet, die die Umsetzung vom Dummy-Device auf die Hardware erledigen, da ein logisches Ein teilweise hardwaremäßig einige Dinge erfordert.&lt;br /&gt;
&lt;br /&gt;
Notify für Pump Low:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
dum_valve:pump_low:.* {&lt;br /&gt;
	if($EVTPART1 eq &amp;quot;on&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set Pool_Pin26 on; sleep 60; set Pool_Pin25 on; sleep 1; set Pool_Pin26 off&amp;quot;);&lt;br /&gt;
	}elsif($EVTPART1 eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set Pool_Pin14 off; sleep 5; set Pool_Pin12 off; sleep 15; set Pool_Pin25 off&amp;quot;);&lt;br /&gt;
	}else{&lt;br /&gt;
	Log3 (&amp;quot;Pool&amp;quot;, 4, qq{Notify Level1 - parameter is not on or off});&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterungen:&lt;br /&gt;
&lt;br /&gt;
* Beim Einschalten ist es nötig für eine Minute Pump High zu aktivieren, um Luft aus der Elektrolysezelle zu spülen, bevor Pump Low aktiv sein darf. (Pin26 und Pin25 sind die Steuerpins auf der Interfacekarte der Pumpe für die beiden Level.)&lt;br /&gt;
* Beim Ausschalten werden zuerst die Salzanlage (Pin14) und die pH-Anlage (Pin12) deaktiviert, damit noch 15 Sekunden lang die Elektrolysezelle mit frischem Wasser gespült wird, um das verbleibende Chlor auszuspülen.&amp;lt;br /&amp;gt;&lt;br /&gt;
Notify für Pump High:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
dum_valve:pump_high:.* {&lt;br /&gt;
	if($EVTPART1 eq &amp;quot;on&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set Pool_Pin26 on; sleep 1; set Pool_Pin25 off&amp;quot;);&lt;br /&gt;
	}elsif($EVTPART1 eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set Pool_Pin25 on; sleep 1; set Pool_Pin26 off&amp;quot;);&lt;br /&gt;
	}else{&lt;br /&gt;
	Log3 (&amp;quot;Pool&amp;quot;, 4, qq{Notify Level 2- parameter is not on or off});&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterung:&lt;br /&gt;
&lt;br /&gt;
* Da die Interfacekarte immer auf den höchsten Level reagiert, wird beim Umschalten zuerst Pump High aktiviert und nach einer Sekunde Pump Low deaktiviert, um ein &amp;quot;stufenloses&amp;quot; (ohne Ausschalten) Umschalten zu ermöglichen. Beim Ausschalten genauso.&lt;br /&gt;
&lt;br /&gt;
Notify für die Wärmepumpe:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
dum_valve:heatpump:.* {&lt;br /&gt;
	if($EVTPART1 eq &amp;quot;on&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set Pool_Pin6 on&amp;quot;);&lt;br /&gt;
	}elsif($EVTPART1 eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set Pool_Pin6 off&amp;quot;);&lt;br /&gt;
	}else{&lt;br /&gt;
	Log3 (&amp;quot;Pool&amp;quot;, 4, qq{Notify heatpump - parameter is not on or off});&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterung:&lt;br /&gt;
&lt;br /&gt;
* Hier reicht ein dirketes Übernehmen aus dem Dummy.&lt;br /&gt;
&lt;br /&gt;
Notify für den Nachbar-Pool:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
dum_valve:pool_kurz:.* {&lt;br /&gt;
	if($EVTPART1 eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; ReadingsVal(&amp;quot;Shelly_Plug_S_1&amp;quot;,&amp;quot;state&amp;quot;,&amp;quot;on&amp;quot;) eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set PwSw_Schalter off; sleep 3;{if(ReadingsAge(\&amp;quot;PwSw_Schalter\&amp;quot;,\&amp;quot;state\&amp;quot;,0)&amp;lt;4 &amp;amp;&amp;amp; ReadingsVal(\&amp;quot;PwSw_Schalter\&amp;quot;,\&amp;quot;state\&amp;quot;,\&amp;quot;on\&amp;quot;) eq \&amp;quot;off\&amp;quot;){fhem(\&amp;quot;set Shelly_Plug_S_1 on\&amp;quot;)}}; sleep 5; set PwSw_Schalter on&amp;quot;);&lt;br /&gt;
	}elsif($EVTPART1 eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; ReadingsVal(&amp;quot;Shelly_Plug_S_1&amp;quot;,&amp;quot;state&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set PwSw_Schalter off; sleep 3;{if(ReadingsAge(\&amp;quot;PwSw_Schalter\&amp;quot;,\&amp;quot;state\&amp;quot;,0)&amp;lt;4 &amp;amp;&amp;amp; ReadingsVal(\&amp;quot;PwSw_Schalter\&amp;quot;,\&amp;quot;state\&amp;quot;,\&amp;quot;on\&amp;quot;) eq \&amp;quot;off\&amp;quot;){fhem(\&amp;quot;set Shelly_Plug_S_1 off\&amp;quot;)}}; sleep 5; set PwSw_Schalter on&amp;quot;);&lt;br /&gt;
	}else{&lt;br /&gt;
	Log3 (&amp;quot;Pool&amp;quot;, 4, qq{Notify Pool Kurz - parameter is not on or off});&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterung&lt;br /&gt;
&lt;br /&gt;
* Da hier eine Pumpe durch einen 3-poligen Umschalter zwischen zwei Hausanspeisungen umgeschaltet wird, ist es wichtig, dass die Pumpe dazwischen &#039;&#039;&#039;gesichert&#039;&#039;&#039; zum Stehen gebracht wird! Sonst führt die rotierende Pumpe als Generator zu einem gewaltigen Kurzschluss mit der &amp;quot;fremden&amp;quot; Phase. War nicht schön ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sonderprogramme für den Poolbetrieb&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Hier ist das Aus- und Einschalten der Solarforcast-Automatik zu sehen. Es werden alle Stati gespeichert. Danach kann von beliebigen &amp;quot;Sonderfunktionen&amp;quot; (Reinigung des Filters, Massagefunktion, usw.) auf die Hardware zugegriffen werden. Wenn wieder in den Automatikmodus zurückgewechselt wird, wird hardwaremäßig wieder der Zustand der Automatik von vorher hergestellt, die Stati wieder zurück geschrieben und die Automatik wieder aktiviert.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
##############################################&lt;br /&gt;
# Status speichern und Automatik ausschalten #&lt;br /&gt;
##############################################&lt;br /&gt;
sub PoolAutoOff{&lt;br /&gt;
	my $pump_low_id			= sprintf &amp;quot;%02d&amp;quot;, 1;&lt;br /&gt;
	my $pump_high_id		= sprintf &amp;quot;%02d&amp;quot;, 3;&lt;br /&gt;
	my $heatpump_id			= sprintf &amp;quot;%02d&amp;quot;, 5;&lt;br /&gt;
	my $pool_kurz_id		= sprintf &amp;quot;%02d&amp;quot;, 7;&lt;br /&gt;
	my $sf				= &#039;energy_mgmt&#039;;&lt;br /&gt;
&lt;br /&gt;
		&lt;br /&gt;
#	my $pump_low_state = ReadingsVal($valve_dummy,&#039;pump_low&#039;,&#039;on&#039;);&lt;br /&gt;
	my $pump_low_auto	= FHEM::SolarForecast::ConsumerVal ($sf, $pump_low_id, &#039;auto&#039;, &#039;&#039;);	# Automatikmodus der Pumpe&lt;br /&gt;
#	my $pump_high_state = ReadingsVal($valve_dummy,&#039;pump_high&#039;,&#039;on&#039;);&lt;br /&gt;
	my $pump_high_auto	= FHEM::SolarForecast::ConsumerVal ($sf, $pump_high_id, &#039;auto&#039;, &#039;&#039;);	# Automatikmodus der Pumpe&lt;br /&gt;
#	my $heatpump_state = ReadingsVal($valve_dummy,&#039;heatpump&#039;,&#039;on&#039;);&lt;br /&gt;
	my $heatpump_auto	= FHEM::SolarForecast::ConsumerVal ($sf, $heatpump_id, &#039;auto&#039;, &#039;&#039;);	# Automatikmodus der Wärmepumpe&lt;br /&gt;
#	my $pool_kurz_state = ReadingsVal($valve_dummy,&#039;pool_kurz&#039;,&#039;on&#039;);&lt;br /&gt;
	my $pool_kurz_auto	= FHEM::SolarForecast::ConsumerVal ($sf, $pool_kurz_id, &#039;auto&#039;, &#039;&#039;);	# Automatikmodus des Pools&lt;br /&gt;
	fhem(&amp;quot;set $valve_dummy pump_low_auto 0&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set $valve_dummy pump_high_auto 0&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set $valve_dummy heatpump_auto 0&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set $valve_dummy pool_kurz_auto 0&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy sf_automatic 0&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_auto_pump_low $pump_low_auto&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_auto_pump_high $pump_high_auto&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_auto_heatpump $heatpump_auto&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_auto_pool_kurz $pool_kurz_auto&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	my $last_pump_level_1 = ReadingsVal($valve_dummy,&amp;quot;pump_low&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	my $last_pump_level_2 = ReadingsVal($valve_dummy,&amp;quot;pump_high&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	my $last_pump_level_3 = ReadingsVal($pump_level_3,&amp;quot;value&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	my $last_pump_level_4 = ReadingsVal($pump_level_4,&amp;quot;value&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	my $last_heatpump = ReadingsVal($valve_dummy,&amp;quot;heatpump&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_pump_level_1 $last_pump_level_1&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_pump_level_2 $last_pump_level_2&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_pump_level_3 $last_pump_level_3&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_pump_level_4 $last_pump_level_4&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_heatpump $last_heatpump&amp;quot;); &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
##########################################&lt;br /&gt;
# Status laden und Automatik einschalten #&lt;br /&gt;
##########################################&lt;br /&gt;
sub PoolAutoOn{&lt;br /&gt;
	my $last_pump_level_4 = ReadingsVal($valve_dummy,&amp;quot;last_pump_level_4&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	my $last_pump_level_3 = ReadingsVal($valve_dummy,&amp;quot;last_pump_level_3&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	my $last_pump_level_2 = ReadingsVal($valve_dummy,&amp;quot;last_pump_level_2&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	my $last_pump_level_1 = ReadingsVal($valve_dummy,&amp;quot;last_pump_level_1&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	my $last_heatpump = ReadingsVal($valve_dummy,&amp;quot;last_heatpump&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set $pump_level_4 $last_pump_level_4&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;set $pump_level_3 $last_pump_level_3&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set $pump_level_2 $last_pump_level_2&amp;quot;);&lt;br /&gt;
	if($last_pump_level_1 eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; $last_pump_level_2 eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $last_pump_level_3 eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $last_pump_level_4 eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set $pump_level_2 on; sleep 1; set $pump_level_1 $last_pump_level_1; sleep 28; set $pump_level_2 off; set $valve_dummy sf_automatic 1&amp;quot;);&lt;br /&gt;
	}elsif($last_pump_level_1 eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; $last_pump_level_2 eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; $last_pump_level_3 eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $last_pump_level_4 eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set $pump_level_1 off; set $valve_dummy sf_automatic 1&amp;quot;); &lt;br /&gt;
	}elsif($last_pump_level_1 eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $last_pump_level_2 eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $last_pump_level_3 eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $last_pump_level_4 eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set $pump_level_1 off; set $valve_dummy sf_automatic 1&amp;quot;); &lt;br /&gt;
	}&lt;br /&gt;
	fhem(&amp;quot;sleep 10; set $heatpump $last_heatpump&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_pump_level_1 none&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_pump_level_2 none&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_pump_level_3 none&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_pump_level_4 none&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_heatpump none&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy valve_position normal&amp;quot;);&lt;br /&gt;
	my $last_auto_pump_low = ReadingsVal($valve_dummy,&amp;quot;last_auto_pump_low&amp;quot;,0);&lt;br /&gt;
	my $last_auto_pump_high = ReadingsVal($valve_dummy,&amp;quot;last_auto_pump_high&amp;quot;,0);&lt;br /&gt;
	my $last_auto_heatpump = ReadingsVal($valve_dummy,&amp;quot;last_auto_heatpump&amp;quot;,0);&lt;br /&gt;
	my $last_auto_pool_kurz = ReadingsVal($valve_dummy,&amp;quot;last_auto_pool_kurz&amp;quot;,0);&lt;br /&gt;
	fhem(&amp;quot;set $valve_dummy pump_low_auto $last_auto_pump_low&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set $valve_dummy pump_high_auto $last_auto_pump_high&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set $valve_dummy heatpump_auto $last_auto_heatpump&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set $valve_dummy pool_kurz_auto $last_auto_pool_kurz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_auto_pump_low none&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_auto_pump_high none&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_auto_heatpump none&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_auto_pool_kurz none&amp;quot;);&lt;br /&gt;
}		&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterungen:&lt;br /&gt;
&lt;br /&gt;
* pump_level_1 ist Pump Low, pump_level_2 ist Pump High, pump_level_3 und pump_level_4 sind Sonderfunktionen (Filterreinigung, Massage)&lt;br /&gt;
* Beim Wiedereinschalten von Pump Low ist es wieder nötig kurz Pump High zu aktivieren, um Luft auszuspülen.&lt;br /&gt;
* Es wird der Zustand von Solarforecast gespeichert und danach auf die Hardware geschrieben. -&amp;gt; Stellt sicher, dass nach dem Einschalten der Automatik der logical switchstate zum physical switchstate passt.&lt;br /&gt;
&lt;br /&gt;
=== Wärmepumpe (Buderus oder Bosch) per MQTT-Modul &amp;amp; BBQKees-EMS-Modul als besonderen ConsumerXX (Heatpump) für die Consumption-Prognose bei den Berechnungen in der AI::FANN einbinden ===&lt;br /&gt;
&#039;&#039;&#039;Vorhandene Hardware:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* FHEM auf einer bestehenden Hardware mit bestehendem Solarforecast&lt;br /&gt;
* Buderus WLW186-i 7 MB AR E&lt;br /&gt;
* WW-Speicher 290 ltr.&lt;br /&gt;
* Heizungspuffer 120 ltr.&lt;br /&gt;
* HK1 = FBH      -                                                         -  mit 1 x HK-Pumpe ON/OFF und 1x Mischer&lt;br /&gt;
* HK2 = (Rest-)Heizkörper im EG/1OG/Handtuchw.    -  mit 1 x HK-Pumpe ON/OFF (ohne Mischer)&lt;br /&gt;
* HK3 = Heizkörper KG (einheitlich max 16 Grad)       -  mit 1 x HK-Pumpe ON/OFF (ohne Mischer)&lt;br /&gt;
* Zusatzheizstab für Sommerbetrieb im WW-Speicher - Nutzung erfolgt nur bei PV-Überschuß tagsüber oder genügend Batterierladung am frühen Morgen gegen 04:00 Uhr.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Anforderungen / notwendige Einstellung :&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* SF ist in Betrieb und die AI::FANN sollte sich aktiv im Einsatz.&lt;br /&gt;
* Wärmepumpe befindet sich dauerhaft im temperaturgeführten Betriebsmodus.&lt;br /&gt;
* BBQKees-EMS-ESP-Modul ist angeschlossen, installiert, in Betrieb und kann per Webbrowser erreicht werden.  Beispieleinrichtung: [[Datei:Einstellung - MQTT - BBQKees.png|ohne|mini|300x300px|Einstellung - MQTT - BBQKees]]&lt;br /&gt;
* &#039;&#039;&#039;MQTT-Modul greift in FHEM auf die WP mittels BBQKees-EMS-Modul zu.&#039;&#039;&#039;   Beispiel-Device:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod MQTT_EMSwp MQTT2_DEVICE MQTT_EMSwp&lt;br /&gt;
attr MQTT_EMSwp DbLogExclude BSSID,IODev,IPv4_address,IPv4_gateway,IPv4_nameserver,IPv6_address,MAC,SSID,apicalls,\&lt;br /&gt;
apifails,attrTemplateVersion,boiler_data_auxheaterdelay,boiler_data_auxheaterlevel,\&lt;br /&gt;
boiler_data_auxheateroff,boiler_data_auxheateronly,\&lt;br /&gt;
boiler_data_auxheatersource,boiler_data_auxheatrmode,boiler_data_auxlimitstart,\&lt;br /&gt;
boiler_data_auxmaxlimit,boiler_data_burn2workmin,\&lt;br /&gt;
boiler_data_burnstarts,boiler_data_burnworkmin,boiler_data_dhw_alternatingop,boiler_data_dhw_altopprio,\&lt;br /&gt;
boiler_data_dhw_altopprioheat,boiler_data_dhw_comfdiff,boiler_data_dhw_comfort1,\&lt;br /&gt;
boiler_data_dhw_comfstop,boiler_data_dhw_disinfecting,boiler_data_dhw_disinfectiontemp,\&lt;br /&gt;
boiler_data_dhw_ecodiff,boiler_data_dhw_ecoplusdiff,\&lt;br /&gt;
boiler_data_dhw_ecoplusoff,boiler_data_dhw_ecoplusstop,boiler_data_dhw_ecostop,\&lt;br /&gt;
boiler_data_dhw_flowtempoffset,boiler_data_dhw_hystoff,boiler_data_dhw_hyston,boiler_data_dhw_maxheat,\&lt;br /&gt;
boiler_data_dhw_onetime,boiler_data_dhw_recharging,boiler_data_dhw_seltemp,\&lt;br /&gt;
boiler_data_dhw_seltemplow,boiler_data_dhw_seltempsingle,boiler_data_dhw_tempecoplus,\&lt;br /&gt;
boiler_data_dhw_workm,bootTime,boot_time,bus_status,connected,freemem,heartbeat_.*,mqttcount,mqttfails,\&lt;br /&gt;
mqttreconnects,network,rssi,rxfails,rxreceived,txfails,txreads,txwrites,uptime,uptime_sec,wifistrength,wifireconnects,\&lt;br /&gt;
thermostat_data_datetime&lt;br /&gt;
attr MQTT_EMSwp autocreate 1&lt;br /&gt;
attr MQTT_EMSwp bridgeRegexp heartbeat:.* { json2nameValue($EVENT) }&lt;br /&gt;
attr MQTT_EMSwp comment&lt;br /&gt;
Autorisierung / Token: \&lt;br /&gt;
The bearer Access Token (JWT) is used to authenticate HTTP requests and can be obtained from the \&lt;br /&gt;
WebUI&#039;s Settings-&amp;gt;Security-&amp;gt;Manage Users page and then clicking on the key icon for the user that has admin privileges (is Admin set). \&lt;br /&gt;
The token is generated using a combination of the username and a secret key which is the super user (su) password found in the WebUI&#039;s Settings-&amp;gt;Security-&amp;gt;Security Settings page. \&lt;br /&gt;
This 152 character long string must be included in the HTTP header as &amp;quot;Authorization: Bearer {ACCESS_TOKEN}&amp;quot;. Note the token has no expiry date.\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;bearer Acts Token&amp;gt; &amp;quot;dieser WLW186-7 MB AR E&amp;quot; = {ACCESS_TOKEN}\&lt;br /&gt;
Beispiele :\&lt;br /&gt;
#############\&lt;br /&gt;
# Most GETs do not need authentication\&lt;br /&gt;
% curl http://ems-esp.local/api/thermostat/seltemp\&lt;br /&gt;
\&lt;br /&gt;
# POSTs (with -d) need authentication tokens\&lt;br /&gt;
% curl http://ems-esp.local/api/thermostat/seltemp \\&lt;br /&gt;
  -H &#039;Content-Type: application/json&#039; \\&lt;br /&gt;
  -H &#039;Authorization: Bearer &amp;lt;bearer Acts Token&amp;gt;&#039; \\&lt;br /&gt;
  -d &#039;{ &amp;quot;value&amp;quot; : 22.5 }&#039;\&lt;br /&gt;
\&lt;br /&gt;
# GET with authentication using query parameter with token\&lt;br /&gt;
% curl http://ems-esp.local/api/system/publish\?access_token\=&amp;quot;ey.......0&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
# GET to restart EMS-ESP\&lt;br /&gt;
curl http://ems-esp.local/api/system/restart -H &#039;Authorization: Bearer ey....0&#039;\&lt;br /&gt;
\&lt;br /&gt;
# This example will get the system info, via a GET request\&lt;br /&gt;
curl -X GET ${emsesp_url}/api/system/info\&lt;br /&gt;
\&lt;br /&gt;
# This example will execute a read command on product ID 8 and type ID 1\&lt;br /&gt;
curl -X POST \\&lt;br /&gt;
    -H &amp;quot;Authorization: Bearer ${&amp;lt;bearer Acts Token&amp;gt;}&amp;quot; \\&lt;br /&gt;
    -H &amp;quot;Content-Type: application/json&amp;quot; \\&lt;br /&gt;
    -d &#039;{&amp;quot;data&amp;quot;:&amp;quot;8 1&amp;quot;}&#039; \\&lt;br /&gt;
    ${emsesp_url}/api/system/read\&lt;br /&gt;
\&lt;br /&gt;
# This example will export all values to a json file, including custom entities, sensors and schedules\&lt;br /&gt;
curl -X POST \\&lt;br /&gt;
    -H &amp;quot;Authorization: Bearer ${&amp;lt;bearer Acts Token&amp;gt;}&amp;quot; \\&lt;br /&gt;
    -H &amp;quot;Content-Type: application/json&amp;quot; \\&lt;br /&gt;
    -d &#039;{&amp;quot;action&amp;quot;:&amp;quot;export&amp;quot;, &amp;quot;param&amp;quot;:&amp;quot;allvalues&amp;quot;}&#039; \\&lt;br /&gt;
    ${emsesp_url}/rest/action&lt;br /&gt;
attr MQTT_EMSwp disable 0&lt;br /&gt;
attr MQTT_EMSwp event-min-interval .*:600&lt;br /&gt;
attr MQTT_EMSwp event-on-change-reading .*&lt;br /&gt;
attr MQTT_EMSwp icon air_water_heating_pump&lt;br /&gt;
attr MQTT_EMSwp model ems-esp_heater_device&lt;br /&gt;
attr MQTT_EMSwp readingList MQTT_EMSwp:ems-esp/heartbeat:.* { json2nameValue($EVENT) }\&lt;br /&gt;
MQTT_EMSwp:ems-esp/status:.* status\&lt;br /&gt;
MQTT_EMSwp:ems-esp/info:.* { json2nameValue($EVENT) }\&lt;br /&gt;
MQTT_EMSwp:ems-esp/heating_active:.* heating_active\&lt;br /&gt;
MQTT_EMSwp:ems-esp/tapwater_active:.* tapwater_active\&lt;br /&gt;
MQTT_EMSwp:ems-esp/boiler_data:.* { json2nameValue($EVENT, &#039;boiler_data_&#039;, $JSONMAP) }\&lt;br /&gt;
MQTT_EMSwp:ems-esp/thermostat_data:.* { json2nameValue($EVENT, &#039;thermostat_data_&#039;, $JSONMAP) }\&lt;br /&gt;
MQTT_EMSwp:ems-esp/mixer_data:.* { json2nameValue($EVENT, &#039;mixer_data_&#039;, $JSONMAP) }&lt;br /&gt;
attr MQTT_EMSwp room EnergieWP,MQTT2_DEVICE&lt;br /&gt;
attr MQTT_EMSwp setList restart:noArg heartbeat:.* { json2nameValue($EVENT) }&lt;br /&gt;
attr MQTT_EMSwp stateFormat T=&amp;gt;&amp;gt;   Out: boiler_data_outdoortemp ModeCirc: thermostat_data_dhw_circmode WW: boiler_data_dhw_curtemp Circ: boiler_data_dhw_circ VL: boiler_data_curflowtemp RL: boiler_data_rettemp HC1-Flow: mixer_data_hc1_flowtemphc   P.-Status HK1: mixer_data_hc1_pumpstatus P.-Status HK2: mixer_data_hc2_pumpstatus  HP_Power_Current: boiler_data_hpcurrpower   HP_Power_Reduction: boiler_data_powerreduction&lt;br /&gt;
attr MQTT_EMSwp userReadings user_WP_JAZ_overall {\&lt;br /&gt;
 if ((ReadingsNum($name,&amp;quot;boiler_data_metertotal&amp;quot;,0) &amp;gt; 0) &amp;amp;&amp;amp; (ReadingsNum($name,&amp;quot;boiler_data_nrgtotal&amp;quot;,0) &amp;gt; 0))\&lt;br /&gt;
 { \&lt;br /&gt;
(sprintf(&amp;quot;%.2f&amp;quot;, (ReadingsNum($name,&amp;quot;boiler_data_nrgtotal&amp;quot;,0)/ReadingsNum($name,&amp;quot;boiler_data_metertotal&amp;quot;,0))));;;;\&lt;br /&gt;
 }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
user_WP_JAZ_year \&lt;br /&gt;
{\&lt;br /&gt;
if ((ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPGridConsumptionYear&amp;quot;,0) &amp;gt; 0) &amp;amp;&amp;amp; (ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPboiler_data_nrgtotalYear&amp;quot;,0) &amp;gt; 0))\&lt;br /&gt;
 { \&lt;br /&gt;
(sprintf(&amp;quot;%.2f&amp;quot;, (ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPboiler_data_nrgtotalYear&amp;quot;,0)/ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPGridConsumptionYear&amp;quot;,1))));;;;\&lt;br /&gt;
 }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
user_WP_JAZ_month {\&lt;br /&gt;
if ((ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPGridConsumptionMonth&amp;quot;,0) &amp;gt; 0)&amp;amp;&amp;amp; (ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPboiler_data_nrgtotalMonth&amp;quot;,0) &amp;gt; 0))\&lt;br /&gt;
 { \&lt;br /&gt;
(sprintf(&amp;quot;%.2f&amp;quot;, (ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPboiler_data_nrgtotalMonth&amp;quot;,0)/ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPGridConsumptionMonth&amp;quot;,1))));;;;\&lt;br /&gt;
 }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
user_WP_JAZ_day {\&lt;br /&gt;
 if ((ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPGridConsumptionDay&amp;quot;,0) &amp;gt; 0) &amp;amp;&amp;amp; (ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPboiler_data_nrgtotalDay&amp;quot;,0) &amp;gt; 0))\&lt;br /&gt;
 { \&lt;br /&gt;
  (sprintf(&amp;quot;%.2f&amp;quot;, (ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPboiler_data_nrgtotalDay&amp;quot;,0)/ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPGridConsumptionDay&amp;quot;,1))));;;;\&lt;br /&gt;
 }\&lt;br /&gt;
}, \&lt;br /&gt;
\&lt;br /&gt;
user_WP_JAZ_hour {\&lt;br /&gt;
 if ((ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPGridConsumptionHour&amp;quot;,0) &amp;gt; 0) &amp;amp;&amp;amp; (ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPboiler_data_nrgtotalhour&amp;quot;,0) &amp;gt; 0))\&lt;br /&gt;
 { \&lt;br /&gt;
  (sprintf(&amp;quot;%.2f&amp;quot;, (ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPboiler_data_nrgtotalhour&amp;quot;,0)/ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPGridConsumptionHour&amp;quot;,1))));;;;\&lt;br /&gt;
 }\&lt;br /&gt;
}, \&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Anmerkung: user_WP_JAZ_XXXX für Tag/Monat/Jahr werden in einem separatem Dummy (für diese Zeiträume) bei mir berechnet.  Allein user_JAZ-overall (Betrachtung der gesamten WP-Betriebszeit) wird in diesem MQTT-Device aus den hier im Device vorhanden Zahlenwerte  berechnet.&lt;br /&gt;
* &#039;&#039;&#039;Definierung des attr Heatpump-&amp;quot;consumerXX&amp;quot; in SF&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
SMA_Elgris_EM2&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt;  EM-Gesamtenergieflüsse der WP&lt;br /&gt;
type=heatpump&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; &amp;quot;Spezial&amp;quot;-Consumer - keine ON/OFF-Schaltung des Consumer durch SF bei Typ heatpump möglich !!!&lt;br /&gt;
power=2500&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; ich untertreibe hier immer etwas extra - es wird bei mir sehr wenig bis zu 3100 W verbraucht&lt;br /&gt;
icon=sani_heating_heatpump@orange&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; oder ein anderes icon nach Wahl oder des Vorhandenseins.&lt;br /&gt;
pcurr=Bezug_Wirkleistung:W&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; aus dem EM&lt;br /&gt;
etotal=Bezug_Wirkleistung_Zaehler:kWh   ## aus dem EM&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; aus dem EM&lt;br /&gt;
switchdev=MQTT_EMSwp&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; wenn man zukünftig evtl. selber schaltent eingreifen möchte&lt;br /&gt;
swstate=boiler_data_hpactivity:heating|cooling|hot.*:off&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; auf die WP-Readings zugreifen &lt;br /&gt;
comforttemp=MQTT_EMSwp:thermostat_data_hc1_comforttemp&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; Komfortemperatur des Referenzraumes (Wert für Prognose AI::FANN) meist der Wohnraum &lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; Komfortemperatur kann auch als fester Wert - z.B. 20 - eingeben werden.fest &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Anmerkung:  Kommentarzeilen bitte besser löschen falls dieser Beispiel-Code 1:1 genutzt werden soll.&lt;br /&gt;
* &#039;&#039;&#039;Definierung des attr &amp;quot;setupEnviroment&amp;quot; in SF&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
outsideTemp=MQTT_EMSwp:boiler_data_outdoortemp&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; Aussentemperatur - alternativ ein anderer T-Füher oder Wetter-App-Wert&lt;br /&gt;
presence=Forecast:user_presence:present&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; Anwesenheit der Bewohner mitteilen - ansonsten geht die AI::FANN in SF immer von &amp;quot;Anwesend&amp;quot; aus&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Anmerkung: &lt;br /&gt;
&lt;br /&gt;
Kommentarzeilen bitte besser löschen falls dieser Beispiel-Code 1:1 genutzt werden soll.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Definierung von notwendigen zusätzlichen &amp;quot;UserReadings&amp;quot; für &amp;quot;presence&amp;quot; in SF:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
user_presence {if(ReadingsVal(&amp;quot;Handy_01&amp;quot;,&amp;quot;state&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;present&amp;quot;) {return &amp;quot;present&amp;quot;} elsif (ReadingsVal(&amp;quot;Handy_02&amp;quot;,&amp;quot;state&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;present&amp;quot;) {return &amp;quot;present&amp;quot;} else {return 0}},&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Anmerkung: Hier wird (über die Fritzbox / PRESENCE - Device) mittels der Handys für 2 Personen die Anwesenheit festgestellt und SF bzw. der AI::FANN über das obige setupEnviroment dann (entweder - oder) als &amp;quot;true&amp;quot; mitgeteilt. Erweiterung auf 3/4/5.... möglich.&lt;br /&gt;
* Definierung der AI::FANN: Beispiel : -&amp;gt; muss nicht zutreffend sein  -&amp;gt; auch ich habe lange getestet und ändere ab und an mal die Einstellung -&amp;gt; Ergänzung bei Einsatz der AI::FANN  (nicht Ersatz für bestehende eintrage ohne AI::FANN)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ergebnis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Im folgenden Bild sieht man das Ergebnis:&lt;br /&gt;
[[Datei:Ergebnis AI-FANN Consumer-Forecast.png|ohne|mini|Ergebnis der AI-FANN Prognose]]&lt;br /&gt;
&lt;br /&gt;
== Tips &amp;amp; Tricks ==&lt;br /&gt;
* Interruptable verhält sich völlig anders, wenn der Perlcode 1 oder 0 liefert, als wenn man 1 oder 0 in der Config hinterlegt. -&amp;gt; siehe commandref&lt;br /&gt;
* Rückgabewert bei swoncond und swoffcond wird mit dem Readingswert verglichen und nicht dirket verwendet. Bsp. wenn das Reading 100 enthält muss auch der Rückgabewert des Perlcodes 100 liefern, um true zu ergeben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== weiterführende Links ==&lt;br /&gt;
* Forenthema &amp;quot;{{Link2Forum|Topic=137058|LinkText=76_SolarForecast - Informationen/Ideen zu Weiterentwicklung und Support}}&amp;quot;&lt;br /&gt;
* Solcast API Toolkit: https://toolkit.solcast.com.au&lt;br /&gt;
* Kostal Plenticore 10 Plus mit SQL-Datenbank Integration ([[Kostal Plenticore 10 Plus]])&lt;br /&gt;
* Photovoltaik Ingenieurbüro Junge: https://www.ing-büro-junge.de/html/photovoltaik.html&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung&amp;diff=41335</id>
		<title>SolarForecast - Solare Prognose (PV Erzeugung) und Verbrauchersteuerung</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung&amp;diff=41335"/>
		<updated>2026-10-11T12:39:14Z</updated>

		<summary type="html">&lt;p&gt;Maista: zwei kleine Verbesserungen&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Modul&lt;br /&gt;
|ModPurpose=Solarprognose und Verbrauchersteuerung&lt;br /&gt;
|ModType=d&lt;br /&gt;
|ModCmdRef=76_SolarForecast&lt;br /&gt;
|ModFTopic=117864&lt;br /&gt;
|ModForumArea=Solaranlagen&lt;br /&gt;
|ModTechName=76_SolarForecast.pm&lt;br /&gt;
|ModOwner=DS_Starter ({{Link2FU|16933|Forum}}/[[Benutzer Diskussion:DS_Starter|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
[[SolarForecast - Solare Prognose (PV Erzeugung) und Verbrauchersteuerung|SolarForecast]] ist ein integratives Modul zur Gewinnung solarer Vorhersagedaten, deren Verarbeitung und grafischen Darstellung. Desweiteren bietet es die Möglichkeit, in FHEM definierte Verbraucher in einem SolarForecast-Device zu registrieren und eine PV Prognose basierte Steuerung der Verbraucher vom Modul übernehmen zu lassen.&lt;br /&gt;
&lt;br /&gt;
Das Modul ist insbesondere durch folgende Eigenschaften gekennzeichnet:&lt;br /&gt;
[[Datei:sfc1.png|right|thumb|300px|grafische Ansicht SolarForecast]]&lt;br /&gt;
&lt;br /&gt;
::* zur Gewinnung solarer Prognosewerte können die SolCast API, OpenMeteo API, Forecast.Solar API, Victron VRM Portal API oder alternativ DWD Stahlungswerte-Stationen verwendet werden&lt;br /&gt;
&lt;br /&gt;
::* optionale KI Unterstützung der PV-Prognose bei Verwendung von geeigneten Solar-APIs&lt;br /&gt;
&lt;br /&gt;
::* optionale KI Unterstützung der Prognose des Energieverbrauchs der kommenden Stunden&lt;br /&gt;
&lt;br /&gt;
::* es wird sowohl die Erzeugungsprognose als auch eine Verbrauchsprognose sowie SoC Prognose (bei Batterie-Integration) erstellt&lt;br /&gt;
&lt;br /&gt;
::* Wetterdaten werden über DWD Wetter-Stationen oder API integriert. Es können verschiedene APIs zur Gewinnung von Solar- und Wetterdaten kombiniert werden. &lt;br /&gt;
&lt;br /&gt;
::* Sprachensupport EN / DE&lt;br /&gt;
&lt;br /&gt;
::* die Prognosedaten, Wetterdaten, Verbraucherplanungen und die aktuellen Energieflüsse werden in umfangreich anpassbaren integrierten Grafiken dargestellt&lt;br /&gt;
&lt;br /&gt;
::* es wird keine externe SQL-Datenbank benötigt, die Datenhaltung erfolgt in einer Memory basierten Cachedatenbank inkl. einer Filesystempersistenz zur Datensicherung und Wiederherstellung beim FHEM-Restart&lt;br /&gt;
&lt;br /&gt;
::* die Integration von Geräten wie Wechselrichter, Energy Meter, Batterien, Wetterstationen oder Verbrauchern ist offen und universell gestaltet und bietet dem Anwender maximale Freiheiten bei der Einrichtung seines individuellen Solardatensystems.&lt;br /&gt;
&lt;br /&gt;
::* eine Integration von bis zu 4 Inverter und Smartloader (DC-DC Batterieladegeräte) ist möglich&lt;br /&gt;
&lt;br /&gt;
::* eine Integration von bis zu 3 nicht PV-Energieerzeugern wie BHKW, Windrädern oder Notstromaggregaten ist möglich&lt;br /&gt;
&lt;br /&gt;
::* eine integrierte und umfangreich anpassbare Verbrauchersteuerung vereint die PV Prognose basierte Einplanung der Verbraucher mit der Möglichkeit die Verbraucher durch das Modul schalten zu lassen und dadurch auf PV Erzeugungsschwankungen automatisch dynamisch zu reagieren&lt;br /&gt;
&lt;br /&gt;
::* Einbindung von bis zu 3 Batteriespeichersystemen&lt;br /&gt;
&lt;br /&gt;
::* Bereitstellung von Leitwerten zur optimalen Einstellung/Steuerung von Batteriespeichersystemen&lt;br /&gt;
&lt;br /&gt;
::* trotz der hohen Komplexität wird dem Anwender durch eine &amp;quot;Guided Procedure&amp;quot; bei der Gerätedefinition der Einstieg erleichtert und damit ein optimales Benutzererlebnis geboten&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Abgrenzung:&#039;&#039;&#039; Das Modul 76_SolarForecast ist nicht zu verwechseln mit der SQL-basierten (DbLog) Prognose-Lösung mit Kostal Plenticore Wechselrichtern, die auf der eigenen Seite &#039;&#039;&#039;[[Kostal_Plenticore_10_Plus]]&#039;&#039;&#039; behandelt wird. Diese Lösung beschreibt kein monolithisches Modul, sondern basiert auf einer orchestrierbaren Zusammenstellung individueller Perl Programmbausteine. &lt;br /&gt;
&lt;br /&gt;
Im vorliegenden Wiki-Beitrag wird ausschließlich das Modul 76_SolarForecast behandelt.&lt;br /&gt;
&lt;br /&gt;
== Rahmenbedingungen und Voraussetzungen ==&lt;br /&gt;
&lt;br /&gt;
Das Wiki gibt allgemeingültige und teilweise sehr spezifische bzw. tiefgehende Informationen und Handlungsempfehlungen zum SolarForecast Modul. Die dargestellten Informationen beziehen sich auf den zum Zeitpunkt der Wiki-Erstellung vorhandenen Entwicklungsstand des Moduls. Durch die stetige Weiterentwicklung können sich Abweichungen zum beschriebenen Inhalt ergeben oder zur Obsoleszenz dieser Inhalte führen. &lt;br /&gt;
&lt;br /&gt;
Vergleiche deshalb die Informationen immer mit der aktuellen Befehls-Referenz zum Modul!&lt;br /&gt;
&lt;br /&gt;
== Definition ==&lt;br /&gt;
Ein SolarForecast Device wird mit dem Befehl&lt;br /&gt;
&lt;br /&gt;
 define &amp;lt;Name&amp;gt; SolarForecast &lt;br /&gt;
&lt;br /&gt;
angelegt. Nach der Definition wird der User durch einen Dialog geführt, der einige unerlässliche Einstellungen abfragt und in den entsprechenden Attributen und Readings persistiert. Alle Attribute und Readings die eine Einstellung der Anlage bewirken, sind mit dem Präfix &amp;quot;setup&amp;quot; versehen. &lt;br /&gt;
&lt;br /&gt;
Die Verwendung von setup-Readings gestattet es die Anlagenparameter dynamisch im Betrieb zu verändern. So kann mit &lt;br /&gt;
&lt;br /&gt;
 set &amp;lt;Name&amp;gt; setupStringAzimuth   bzw.&lt;br /&gt;
 set &amp;lt;Name&amp;gt; setupStringDeclination &lt;br /&gt;
&lt;br /&gt;
die Ausrichtung und der Neigungswinkel der PV-Module ständig angepasst werden, was zum Beispiel bei einer dem Sonnenstand nachgeführten Anlage von Bedeutung ist.&lt;br /&gt;
&lt;br /&gt;
Die abgefragten Einstellungen während des Dialoges sind ausführlich in den entsprechenden Attributen bzw. Set-Kommandos erläutert. Die benötigten Informationen sind anhängig von der gewählten Prognose-API und können im Umfang variieren.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2024-09-21 213257.png|right|thumb|400px|Anlagenprüfung über Drucktaste in der Kopfgrafik]]&lt;br /&gt;
&lt;br /&gt;
Sobald alle verlangten Einstellungen vorgenommen sind, sollte eine Anlagenprüfung mit &lt;br /&gt;
&lt;br /&gt;
 set &amp;lt;Name&amp;gt; plantConfiguration check&lt;br /&gt;
&lt;br /&gt;
oder über die angebotene Drucktaste in der Grafik durchgeführt werden. Es wird eine Plausibilitätsprüfung vorgenommen und das Ergebnis sowie eventuelle Hinweise bzw. Fehler ausgegeben.&lt;br /&gt;
Die Prüfung kann beliebig wiederholt werden und sollte sich bei jeder Einstellungsänderung der Anlage durchgeführt werden. Dadurch wird die Wahrscheinlichkeit von fehlerhaften Einstellungen minimiert.&lt;br /&gt;
&lt;br /&gt;
Neben den grundlegenden Einstellungen können im Device weitere sekundäre Anlagenkomponenten wie Batteriesystem(e) (Attribut setupBatteryDev1 - setupBatteryDev3), weitere Wetter-Devices (Attribut setupWeatherDev1 - setupWeatherDev3) oder sonstige Erzeuger (z.B. BHKW, Winderzeugung, Notstromaggregat) integriert werden (Attribut setupOtherProducer01 - setupOtherProducer03).&lt;br /&gt;
&lt;br /&gt;
Die verlangten Parameter der Anlage werden in der Online-Hilfe umfassend beschrieben und deren Funktion erschließt sich zum größten Teil selbst. Dennoch soll nachfolgend auf einige Punkte im Zusammenhang der Einrichtung eingegangen werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Hinweise zur Struktur der Attribute ===&lt;br /&gt;
&lt;br /&gt;
Durch die umfangreichen Funktionen des Moduls würde bei Nutzung der im FHEM herkömmlich vorhandenen Attributstruktur die Anzahl der benötigten Attribute extrem stark steigen und nicht sinnvoll genutzt werden können. Deshalb gibt es neben den &#039;&#039;gewöhnlichen&#039;&#039; Attributen mit einfachen Werteauswahlmöglichkeiten oder Eingaben (z.B. ctrlDebug, ctrlSpecialReadings) sogenannte &#039;&#039;zusammengesetzte&#039;&#039; Attribute, deren Inhalt durch &#039;&#039;&#039;Schlüssel=Wert Paare&#039;&#039;&#039; gebildet wird und dadurch deutlich mehr Funktionen und Informationen transportieren als ein gewöhnliches Attribut.&lt;br /&gt;
&lt;br /&gt;
Für zusammengesetzte Attribute besteht die zusätzliche Möglichkeit, gewünschte Änderungen der Schlüssel=Wert Paare selektiv vornehmen zu können, ohne das gesamte Attribut aufrufen und ändern zu müssen. Die Vorgang, der vor allem für programmtechnische Manipulationen gedacht ist, kann durch eine Set-Funktion ausgeführt werden:&lt;br /&gt;
&lt;br /&gt;
 set &amp;lt;Name&amp;gt; attrKeyVal &amp;lt;Attribut&amp;gt; [&amp;lt;Gerät&amp;gt;] &amp;lt;Schlüssel=Wert&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiele für zusammengesetzte Attribute sind:&lt;br /&gt;
&lt;br /&gt;
* aiControl&lt;br /&gt;
* plantControl&lt;br /&gt;
* setup* Attribute&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Funktionen der Attribute werden durch einen Präfix geclustert und so inhaltlich, aber vor allem auch in der Attribute Drop-Down Liste, strukturiert dargestellt.&lt;br /&gt;
&lt;br /&gt;
Die Bedeutung der &#039;&#039;&#039;Präfixe&#039;&#039;&#039; sind:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ai&#039;&#039;&#039; - Steuerungsfunktionen für KI (z.B. aiControl)&lt;br /&gt;
* &#039;&#039;&#039;consumer&#039;&#039;&#039; - Registrierung und Einstellungen für Verbraucher (z.B. consumer02, consumerControl)&lt;br /&gt;
* &#039;&#039;&#039;ctrl&#039;&#039;&#039; - Steuerungsfunktion allgemeiner Art (z.B. ctrlDebug, ctrlSpecialReadings, ctrlUserExitFn)&lt;br /&gt;
* &#039;&#039;&#039;flowGraphic&#039;&#039;&#039; - Einstellungen für die Energieflußgrafik (z.B. flowGraphicControl)&lt;br /&gt;
* &#039;&#039;&#039;graphic&#039;&#039;&#039; - Einstellung für die Grafik allgemein (z.B. graphicSelect, graphicControl)&lt;br /&gt;
* &#039;&#039;&#039;graphicBeam&#039;&#039;&#039; -  Einstellungen bestimmte Balkeneigenschaften in der Balkengrafik (z.B. graphicBeamHeightLevel1)&lt;br /&gt;
* &#039;&#039;&#039;plant&#039;&#039;&#039; - übergreifende Einstellungen betreffend der gesamten PV-Anlage bzw. des SolarForecast-Devices (z.B. plantControl)&lt;br /&gt;
* &#039;&#039;&#039;setup&#039;&#039;&#039; - Registrierung von Geräten in der Gesamtanlage und Einstellung deren Eigenschaften (Inverter, Zähler, Batterien usw.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Einrichtung der Wechselrichter mit setupInverterDevXX ===&lt;br /&gt;
&lt;br /&gt;
Mit den Attributen setupInverterDev01 bis setupInverterDevXX werden die vorhandenen Wechselrichter der Anlage registriert.&lt;br /&gt;
Das Modul unterscheidet verschiedene Wechselrichter-Typen, die sich durch ihre Arbeitsweise innerhalb der Anlage unterscheiden. Die Schlüssel=Wert Paare in den Attributen können mehrzeilig organisiert werden. Das erleichtert die Übersicht wenn viele dieser Parameter eingegeben werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;PV-Wechselrichter: Es ist der Standard Wechselrichter in einer PV-Anlage. An ihn sind die Solarzellen bzw. Strings angeschlossen. Die zugeordneten Strings können mit dem Schlüssel &#039;&#039;&#039;strings&#039;&#039;&#039; zugeordnet werden. Ohne diese Angabe werden diesem Gerät alle definierten Strings (siehe Attribut &#039;&#039;setupInverterStrings&#039;&#039;) zugeordnet. Der Wechselrichter liefert seine Energie in das Hausnetz. Alternativ kann mit der Angabe &#039;&#039;&#039;feed=grid&#039;&#039;&#039; die Funktion des Wechselrichters geändert werden. Diese Angabe sagt aus, dass dieser Wechselrichter ausschließlich in das öffentliche Netz einspeist.&lt;br /&gt;
&lt;br /&gt;
Hier ein Beispiel-Setup eines PV-Wechselrichters (SMA STP):&lt;br /&gt;
&lt;br /&gt;
 STP_5000 pvIn=string_1_pdc:kW pvOut=total_pac:kW etotal=etotal:kWh capacity=5000 strings=Süddach asynchron=1 limit=100&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Solar-Ladegeräte: Solar-Ladegeräte sind DC-DC Wandler und liefern die Energie der angeschlossenen Solarzellen nicht in das Wechselstromnetz, sondern laden direkt eine Batterie bzw. versorgen einen Batteriewechselrichter auf der Gleichstromseite. Die Funktion als Solar-Ladegerät wird mit &#039;&#039;&#039;feed=bat&#039;&#039;&#039; aktiviert, die relevanten Strings können ebenfalls mit dem Schlüssel &#039;&#039;&#039;strings&#039;&#039;&#039; zugeordnet werden. Ein Beispiel eines Solar-Ladegerätes ist ein Victron SmartSolar MPPT. &lt;br /&gt;
&lt;br /&gt;
Ein Beispiel für das Setup eines Solar-Ladegeräts (SmartSolar Charger MPPT):&lt;br /&gt;
&lt;br /&gt;
 MQTT2_cerboGX_c0619ab34e08_solarcharger_Common pv=Yield_Power_value:W etotal=Yield_System_value:kWh capacity=2080 strings=Schleppdach feed=bat synchron=0 limit=100&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Batterie-Wechselrichter: Dieses Gerät hat keine angeschlossenen Solarzellen und arbeitet als DC-AC bzw. AC-DC Wandler zwischen einer Batterie (=Gleichstromquelle) und dem Wechselstrom-Hausnetz. Die Funktion als Batterie-Wechselrichter wird mit der Angabe &#039;&#039;&#039;strings=none&#039;&#039;&#039; aktiviert. Die Schlüssel &#039;&#039;etotal&#039;&#039; und &#039;&#039;pv&#039;&#039; können bei einem Batterie-Wechselrichter ohne zugeordnete Solarzellen nicht gesetzt werden. Ein Beispiel eines Batterie-Wechselrichter ist der Victron MultiPlus II.&lt;br /&gt;
&lt;br /&gt;
Ein Setup-Beispiel für einen Batterie-Wechselrichter (Victron MultiPlus II):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dc2ac=DC_IN:W&lt;br /&gt;
ac2dc=DC_OUT:W&lt;br /&gt;
capacity=7200&lt;br /&gt;
strings=none&lt;br /&gt;
icon=inverter@darkorange:inverter@grey&lt;br /&gt;
asynchron=0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Eigenschaften des Wechselrichters werden durch eine Reihe von &amp;lt;Schlüssel=Wert&amp;gt; Paaren festgelegt. Auf einige dieser Paramter soll hier eingegangen werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Ausgewählte Schlüssel=Wert Paare ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;pvIn=&amp;lt;Readingname&amp;gt;:&amp;lt;Einheit&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
	&lt;br /&gt;
Dem Schlüssel &#039;&#039;pvIn&#039;&#039; wird ein Reading und dessen Einheit (W,kW) des Wechselrichter-Device zugeordnet, welches die aktuell zugeführte PV-Leistung bereitstellt. Der Schlüssel ist optional und dient in erster Linie dazu den entsprechenden Input-Wert in der Flußgrafik anzuzeigen sofern man das Attribut flowGraphicControl-&amp;gt;showGenerators=1 setzt. Dadurch ist auch der Eigenverbrauch des Inverters bzw. dessen Wandlungsverlust visuell abschätzbar.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;pvOut=&amp;lt;Readingname&amp;gt;:&amp;lt;Einheit&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
	&lt;br /&gt;
Dem Schlüssel &#039;&#039;pvOut&#039;&#039; wird ein Reading und dessen Einheit (W,kW) des Wechselrichter-Device zugeordnet, welches die aktuell erzeugte Leistung als positiven Wert liefert. Für einen PV-Wechselrichter (DC-&amp;gt;AC) oder Solar-Ladegerät (DC-&amp;gt;DC) ist es die erzeugte PV-Leistung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ac2dc=&amp;lt;Readingname&amp;gt;:&amp;lt;Einheit&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dieser Schlüssel ist nur für einen Batterie-Wechselrichter setzbar. Das Reading liefert die aktuelle Leistung, die der Wechselrichter vom Hausnetz in Richtung Batterie (AC-&amp;gt;DC) wandelt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dc2ac=&amp;lt;Readingname&amp;gt;:&amp;lt;Einheit&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dieser Schlüssel ist nur für einen Batterie-Wechselrichter setzbar. Das Reading liefert die aktuelle Leistung, die der Wechselrichter aus einer Gleichstromquelle, d.h. einer Batterie oder einem Solar-Ladegerät, in Richtung des Hausnetzes (AC) wandelt . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;capacity=&amp;lt;max. WR-Leistung&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In dem Schlüssel &#039;&#039;capacity&#039;&#039; wird die maximal mögliche Leistung in Watt (ohne Einheit) angegeben, die der Wechselrichter lt. seinem Datenblatt in der Lage ist zu leisten. &lt;br /&gt;
&lt;br /&gt;
Die Angabe &#039;&#039;capacity&#039;&#039; hat in erster Linie die Aufgabe, die max. mögliche PV-Leistung für die Prognose zu begrenzen. Oft sind die installierten Peak-Leistungen der PV-Module höher als die angeschlossene Wechselrichter-Leistung bzw. kommt es vor, dass die KI / (korrigierte) API-Prognose über der maximal möglichen Wechselrichter-Leistung liegt. In diesen Fällen wird die Prognose auf die angegebene &#039;&#039;capacity&#039;&#039; begrenzt.&lt;br /&gt;
&lt;br /&gt;
Der Wert in diesem Schlüssel kann, wie andere Schlüssel auch, dynamisch zur Laufzeit mit dem Set-Befehl &amp;quot;[[#Hinweise zur Struktur der Attribute|set &amp;lt;Name&amp;gt; attrKeyVal ...]]&amp;quot; geändert werden. Ein Beispiel zur Anwendung ergibt sich aus folgendem Szenario.&lt;br /&gt;
&lt;br /&gt;
Gegeben sei eine Anlage die aus Solarzellen (1300 W Peak) mit einem Solar-Ladegerät mit max. 1800 W Leistung, einer Batterie und einem Batterie-Wechselrichter besteht. Die Anlage versorgt nur das Hausnetz. Eine Netzeinspeisung ist nicht vorgesehen oder nicht erlaubt.  &lt;br /&gt;
&lt;br /&gt;
Nehmen wir an, es ist ein Tag voller Sonnenschein prognostiziert und die Batterie ist zunächst entladen. Der Haushalt verbraucht 300 W. Dann würden die PV-Module Module ihre volle Leistung von 1300 W Peak leisten können, die sich auch in der Balken-Vorhersage niederschlägt. Die Leistung wird nicht begrenzt, weil:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* sie niedriger ist als die nominale und angegebene Wechselrichter Kapazität von &#039;&#039;capacity=1800&#039;&#039;&lt;br /&gt;
* die erzeugte Energie anteilig für die Verorgung des Hauses und die Aufladung der Batterie verwendet wird&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Anders verhält es sich wenn nach einer gewissen Zeit die Batterie voll ist und weiterhin volle PV Leistung zur Verfügung steht. In diesem Fall würde der Haushalt seine benötigte Leistung von 300 W abnehmen, aber das Solar-Ladegerät kann keine weitere Leistung mehr abgeben, da die Batterie bereits voll geladen ist, d.h. die Anlagensteuerung würde die PV-Anlage abregeln. In diesem Fall, wenn es einen längeren Zeitraum betrifft, muß auch die Prognose PV-Energie auf 300 Wh (bzw. den durchschnittlichen Energieverbrauch des Hauses pro Stunde) begrenzt werden, damit die PV-Prognose nach unten angepasst wird und so eine realitätsnahere Prognose ermöglicht wird. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;icon=&amp;lt;aktiv&amp;gt;[@&amp;lt;Farbe&amp;gt;][:&amp;lt;inaktiv&amp;gt;[@&amp;lt;Farbe&amp;gt;]]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Jeder Wechselrichter wird im Standard durch ein Icon getrennt nach Tag und Nacht, d.h. je nach Aktiv-Status und Inaktiv-Status, symbolisiert.&lt;br /&gt;
&lt;br /&gt;
;Tag bzw. Aktivität: Für Wechselrichter mit angeschlossenen PV-Modulen wird ein entsprechend gefärbtes Sonnensymbol im Standard verwendet. Batterie-Wechselrichter verwenden ein gefärbtes Invertersymbol.&lt;br /&gt;
&lt;br /&gt;
;Nacht bzw. Inaktivität: Für Wechselrichter mit angeschlossenen PV-Modulen wird ein entsprechend gefärbtes Symbol der aktuellen Mondphasen im Standard verwendet. Batterie-Wechselrichter verwenden ein ausgegrautes Invertersymbol.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wie angegeben, kann man für Tag und Nacht jeweils ein Wunsch-Icon, wenn gewünscht mit einer alternativen Färbung, auswählen.&lt;br /&gt;
&lt;br /&gt;
 icon=inverter@darkorange:inverter@gray&lt;br /&gt;
&lt;br /&gt;
Soll nur das Icon für die Nacht bzw. Inaktivät geändert werden, kann dies in dieser Form angegeben werden:&lt;br /&gt;
&lt;br /&gt;
 icon=:inverter@gray  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(beachte den führenden &#039;:&#039;)&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Definition von Hybrid-Wechselrichtern  ====&lt;br /&gt;
&lt;br /&gt;
Zur Zeit der Erstellung dieses Abschnittes ist es in der SolarForecast Version 1.58.x nicht möglich, einen Hybridwechselrichter nativ zu definieren. Als Workaround wird eine passende Kombination aus PV-Wechselrichter und Batterie-Device oder einer Kombination aus PV-Wechselrichter + Batterie-Wechselrichter und Batterie-Device erstellt.&lt;br /&gt;
&lt;br /&gt;
Bei allen benutzten Methoden ist es sehr wichtig!, dass die geforderten Inhalte der jeweilige Attributschlüssel beachtet und eingehalten werden. So ist zum Beispiel die Angabe von:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;pvOut&#039;&#039;&#039; - Ein Reading, welches die aktuelle Leistung aus PV-Erzeugung, die an das Hausnetz oder öffentliche Netz geliefert wird, bereitstellt. Es wird ein positiver numerischer Wert erwartet.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
bei einem PV-Wechselrichter ein Reading welches ausschließlich die Leistung liefert, die von den Solarzellen-Generatoren erzeugt wird. Elemente von Batterieleistungen oder Gridbestandteile dürfen hier nicht enthalten sein. Sind in den Gerätemodulen diese Readings in dieser Form nicht enthalten, bietet es sich an, userReadings zur Erstellung von zusätzlichen Readings in den Quellendevices zu nutzen um den nötigen Input für SolarForecast bereitzustellen. &lt;br /&gt;
&lt;br /&gt;
So wird zum Beispiel bei einem 	Batterie-Wechselrichter gefordert, dass die Readings &#039;&#039;&#039;ac2dc&#039;&#039;&#039; (AC-&amp;gt;DC-Leistung Hausnetz zur Batterie) und &#039;&#039;&#039;dc2ac&#039;&#039;&#039; (DC-&amp;gt;AC-Leistung (Batterie zum Hausnetz) &#039;&#039;&#039;jeweils als als positiver Wert&#039;&#039;&#039; anzugeben ist. Manche Batterie-Devices stellen allerdings nur ein Reading zur Verfügung, welches vorzeichenbehaftet die Leistungen in die Batterie bzw. aus der Batterie heraus liefert. Mit einem userReadings Attribut kann aus diesem Reading zwei neue Readings erzeugt werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr &amp;lt;Name&amp;gt; userReadings  BatIn:DC_Power_value.* {&lt;br /&gt;
                          my $pwr = ReadingsVal ($name, &#039;DC_Power_value&#039;, 0);&lt;br /&gt;
                          $pwr    = $pwr &amp;gt; 0 ? $pwr : 0;&lt;br /&gt;
                          $pwr&lt;br /&gt;
                          },&lt;br /&gt;
                          BatOut:DC_Power_value.* {&lt;br /&gt;
                          my $pwr = ReadingsVal ($name, &#039;DC_Power_value&#039;, 0);&lt;br /&gt;
                          $pwr    = $pwr &amp;lt; 0 ? - $pwr : 0;&lt;br /&gt;
                          $pwr&lt;br /&gt;
                          },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ist das Quellenreading &#039;&#039;DC_Power_value&#039;&#039; positiv, stellt der Wert AC-&amp;gt;DC-Leistung dar und wird als neues Reading BatIn bereitgestellt. Mit einem negativen Vorzeichen ist es eine DC-&amp;gt;AC-Leistung und wird in dem neuen Reading BatOut &#039;&#039;&#039;ebenfalls als positiver Wert&#039;&#039;&#039; bereitgestellt. Auch hier gilt der Grundsatz, dass zum Beispiel BatOut nur die von der Batterie gelieferte Energie und keinen Mix aus Batterie- und PV-Energie enthalten darf.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
===== Integration eines DEYE SUN-12K-SG04LP3-EU =====&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2025-09-23 203955.png|right|thumb|400px|DEYE SUN-12K-SG04LP3-EU Grundlegende Systemarchitektur]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der DEYE vereint wie wohl alle bzw. die meisten Hybrid-Wechselrichter die Anschlüsse:&lt;br /&gt;
&lt;br /&gt;
* Eingang Solar-Strings&lt;br /&gt;
* Anschluß Batteriespeicher&lt;br /&gt;
* AC-Anschluß öffnetliches Netz&lt;br /&gt;
* AC-Anschluß Ersatzlast (wird bei Netzausfall weiter versorgt)&lt;br /&gt;
* AC-Anschluß Notstromgenerator bzw. netzgekoppelter anderer Wechselrichter (hier ist ein Growatt Micro-Wechselrichter angeschlossen)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Für die Integration werden die setup-Attribute durch das FHEM Device &#039;&#039;Deye_Inverter&#039;&#039; besetzt:&lt;br /&gt;
&lt;br /&gt;
* setupInverterStrings zur Definition der vorhandenen Solarstrings&lt;br /&gt;
* setupInverterDev01 zur Definition der Inverteranschlüsse und Eigenschaften&lt;br /&gt;
* setupBatteryDev01 integriert die Batterie&lt;br /&gt;
* setupMeterDev liefert die Daten für Netzbezug und Netzeinspeisung&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das nachfolgend verwendete Device &#039;&#039;Deye_Inverter&#039;&#039; ist ein MQTT-Device. Es bekommt Daten vom Deye-Hybridwechselrichter per MQTT und sendet Einstellungen zum Deye, bspw. maximaler Lade/Entladestrom des Akkus, Laden des Akkus aus dem Netz, Ein- und Ausschalten des Micro-Inverter-Ports.&lt;br /&gt;
Das Reading &#039;&#039;Deye_Growatt_power&#039;&#039; im Schlüssel &#039;&#039;pvOut&#039;&#039; ist eine Addition aus den Daten des Deye WR und des angeschlossenen Growatt Micro-Wechselrichters.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr &amp;lt;Name&amp;gt; setupInverterStrings Sueddach,Garagendach&lt;br /&gt;
attr &amp;lt;Name&amp;gt; setupInverterDev01 Deye_Inverter pvOut=Deye_Growatt_power:W capacity=15200 etotal=total_pv_production:kWh&lt;br /&gt;
attr &amp;lt;Name&amp;gt; setupBatteryDev01 Deye_Inverter pin=-pout pout=battery_output_power:W intotal=total_charge_of_the_battery:kWh outtotal=total_discharge_of_the_battery:kWh cap=15200 charge=SOC_jkbms&lt;br /&gt;
attr &amp;lt;Name&amp;gt; setupMeterDev Deye_Inverter gcon=total_grid_power:W contotal=total_energy_bought:kWh gfeedin=-gcon feedtotal=total_energy_sold:kWh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;setupInverterStrings&#039;&#039; benennt alle vorhandenen Solarstrings. Werden mehrere Inverter definiert, kann mit dem hier nicht verwendeten Schlüssel &#039;&#039;strings&#039;&#039; eine Zuordnung der Strings zum angeschlossenen Inverter vorgenommen werden.&lt;br /&gt;
&lt;br /&gt;
Im Attribut &#039;&#039;setupInverterDev01&#039;&#039; ist der allgemeine Schlüssel &#039;&#039;capacity&#039;&#039; zur Festlegung der Inverterleistung von 15200 Watt gesetzt. Die spezifischen Schlüssel &#039;&#039;pvOut&#039;&#039; und &#039;&#039;etotal&#039;&#039; teilen dem Modul die aktuell erzeugte PV-Leistung sowie die gesamte erzeugte PV-Energie mit. Letzteres dient unter anderem dazu die stündlich real erzeugte PV-Energie festzuhalten und mit der Prognose zu vergleichen. Die in den schlüsseln hinterlegten dürfen keine Batterie- oder Netzanteile enthalten.&lt;br /&gt;
&lt;br /&gt;
Das Attr &#039;&#039;setupBatteryDev01&#039;&#039; implementiert alle relevanten Batteriewerte. Das Reading &#039;&#039;battery_output_power&#039;&#039; im Schlüssel &#039;&#039;pout&#039;&#039; liefert den Batterie-Output als positiven Wert. Als Besonderheit kann der Wert &#039;&#039;pin&#039;&#039;, die Batterie-Ladeleistung, den Wert des Readings in &#039;&#039;pout&#039;&#039; übernehmen wenn dieser Wert ein negatives Vorzeichen hat. Die Schlüssel &#039;&#039;intotal&#039;&#039; und &#039;&#039;outtotal&#039;&#039; liefern die summierten Totalwerte für Batterie Ladung bzw. Entladung. Die Kapazität &#039;&#039;cap&#039;&#039; wird für verschiedene Aspekte der SoC- und Ladesteuerung verwendet. &lt;br /&gt;
&lt;br /&gt;
Abschließend liefern die angegebenen Readings in den Schlüsseln des Attributes &#039;&#039;setupMeterDev&#039;&#039; alle notwendigen Werte des Netzbezugs und der Netzeinspeisung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nachfolgende Links liefern &#039;&#039;&#039;weitere Infos&#039;&#039;&#039; wie man Daten aus dem Deye WR ausliest und Einstellungen des Deye WR verändert:&lt;br /&gt;
&lt;br /&gt;
* https://github.com/klatremis/esphome-for-deye&lt;br /&gt;
* https://github.com/philipphenkel/esphome-config&lt;br /&gt;
* https://github.com/bagges/deye-esp32-bridge&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Für eine weiterführende Automation soll der Akku netzdienlich in der Mittagszeit geladen werden. Dazu wurde durch den Anwender folgendes userReadings &#039;&#039;MaxBattCharge_Request&#039;&#039; im Device &#039;&#039;Deye_Inverter&#039;&#039; für den maximalen Ladestrom definiert (bei 90% SOC und bei 100% SOC):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MaxBattCharge_Request:SOC_jkbms.* {&lt;br /&gt;
                                    if ((ReadingsNum(&#039;mySolarForecast&#039;,&#039;RestOfDayPVforecast&#039;,&#039;&#039;)&lt;br /&gt;
                                         - ReadingsNum(&#039;mySolarForecast&#039;,&#039;special_todayConForecastTillSunset&#039;,&#039;&#039;)&lt;br /&gt;
                                         - (90-ReadingsNum(&#039;JK_BMS&#039;,&#039;capacity_remaining&#039;,&#039;&#039;))/100*310*51.2) &amp;lt; 400&lt;br /&gt;
                                         and ReadingsAge(&#039;JK_BMS&#039;,&#039;capacity_full_timestamp&#039;,&#039;&#039;) &amp;lt; 561600)&lt;br /&gt;
                                    {100}&lt;br /&gt;
                                    elsif ((ReadingsNum(&#039;mySolarForecast&#039;,&#039;RestOfDayPVforecast&#039;,&#039;&#039;)&lt;br /&gt;
                                            - ReadingsNum(&#039;mySolarForecast&#039;,&#039;special_todayConForecastTillSunset&#039;,&#039;&#039;)&lt;br /&gt;
                                            - (100-ReadingsNum(&#039;JK_BMS&#039;,&#039;capacity_remaining&#039;,&#039;&#039;))/100*310*51.2) &amp;lt; 400&lt;br /&gt;
                                            and ReadingsAge(&#039;JK_BMS&#039;,&#039;capacity_full_timestamp&#039;,&#039;&#039;) &amp;gt;= 561600)&lt;br /&gt;
                                    {100}&lt;br /&gt;
                                    elsif ((ReadingsNum(&#039;mySolarForecast&#039;,&#039;RestOfDayPVforecast&#039;,&#039;&#039;)&lt;br /&gt;
                                            - ReadingsNum(&#039;mySolarForecast&#039;,&#039;special_todayConForecastTillSunset&#039;,&#039;&#039;)&lt;br /&gt;
                                            - (90-ReadingsNum(&#039;JK_BMS&#039;,&#039;capacity_remaining&#039;,&#039;&#039;))/100*310*51.2) &amp;gt;= 400&lt;br /&gt;
                                            and ReadingsAge(&#039;JK_BMS&#039;,&#039;capacity_full_timestamp&#039;,&#039;&#039;) &amp;lt; 561600)&lt;br /&gt;
                                    {ceil ((90-ReadingsNum(&#039;JK_BMS&#039;,&#039;capacity_remaining&#039;,&#039;&#039;))/100*310/3.5)}&lt;br /&gt;
                                    elsif ((ReadingsNum(&#039;mySolarForecast&#039;,&#039;RestOfDayPVforecast&#039;,&#039;&#039;)&lt;br /&gt;
                                            - ReadingsNum(&#039;mySolarForecast&#039;,&#039;special_todayConForecastTillSunset&#039;,&#039;&#039;)&lt;br /&gt;
                                            - (100-ReadingsNum(&#039;JK_BMS&#039;,&#039;capacity_remaining&#039;,&#039;&#039;))/100*310*51.2) &amp;gt;= 400&lt;br /&gt;
                                            and ReadingsAge(&#039;JK_BMS&#039;,&#039;capacity_full_timestamp&#039;,&#039;&#039;) &amp;gt;= 561600)&lt;br /&gt;
                                    {ceil ((100-ReadingsNum(&#039;JK_BMS&#039;,&#039;capacity_remaining&#039;,&#039;&#039;))/100*310/3.0)}&lt;br /&gt;
                                  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das userReading wird in einer Automation benutzt, um den maximalen Ladestrom einzustellen; Ladebeginn bei ausreichend Sonne ist ab 11:30 eingestellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
===== Integration eines Fronius Symo GEN24 10.0 Plus mit (virtuellen) Batterie-Wechselrichter =====&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2025-10-04 162422.png|right|thumb|400px|Flußgrafik mit eingebauten Hybrid-Wechselrichter]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Integration des Wechselrichters Fronius Symo GEN24 10.0 Plus benötigt zunächst eine Anbindung in FHEM, was mit dem Modul 98_fronius.pm vorgenommen wurde.&lt;br /&gt;
&lt;br /&gt;
Das Ziel der Kurzdokumentation ist neben der Darstellung eines Hybridwechselrichters aufzuzeigen, wie man den Wandlungsverlust eines PV-Wechselrichters (pvIn – pvOut) in Näherung visualisieren kann.  &lt;br /&gt;
&#039;&#039;&#039;pvIn&#039;&#039;&#039; ist dabei die Summe der Produkte aus den DC Strom- und Spannungswerten der einzelnen Strings (hier 2109 W), &#039;&#039;&#039;pvOut&#039;&#039;&#039; (hier 2065 W) ist die an den Inverterknoten (hier 1105 W) plus die an die Batterie abgegebene Leistung (hier 960 W). Bei dieser Implementierung wird mit einem zusätzlichen (virtuellen) Batterie-Wechselrichter gearbeitet. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In Vorbereitung werden die beiden anzugebenden Readings &#039;&#039;&amp;lt;pvIn&amp;gt;&#039;&#039; und &#039;&#039;&amp;lt;pvOut&amp;gt;&#039;&#039; zum Beispiel als userReadings erstellt, wobei &#039;&amp;lt;pvIn&amp;gt;&#039;&#039; und &#039;&#039;&amp;lt;pvOut&amp;gt;&#039;&#039; natürlich durch Readingnamen ersetzt werden müssen. Diese beiden Readings werden wie folgt berechnet / erstellt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;pvOut&amp;gt; = Inverter_Common_PAC_Value - PowerFlow_Site_P_Akku&lt;br /&gt;
&amp;lt;pvIn&amp;gt; = Inverter_Common_IDC_Value * Inverter_Common_UDC_Value + Inverter_Common_IDC_2_Value * Inverter_Common_UDC_2_Value&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;&#039;PV-Wechselrichter&#039;&#039;&#039; wird mit dem Attribut setupInverterDev01 definiert, wobei die angelegten Readingnamen in den Schlüsseln &#039;&#039;pvIn&#039;&#039; bzw. &#039;&#039;pvOut&#039;&#039; verwendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SymGen24 icon=inverter@#ff8c00:inverter@grey capacity=10000 strings=suedwest,nordost etotal=User_Produced_PV:kWh pvOut=&amp;lt;pvOut&amp;gt;:W pvIn=&amp;lt;pvIn&amp;gt;:W&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem PV-Wechselrichter sind die Strings &#039;&#039;suedwest&#039;&#039; und &#039;&#039;nordost&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Der zusätzliche &#039;&#039;&#039;Batterie-Wechselrichter&#039;&#039;&#039; wird mit dem Attribut setupInverterDev02 hinzugefügt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SymGen24 icon=inverter@#ff8c00:inverter@grey strings=none ac2dc=-PowerFlow_Site_P_Akku:W  dc2ac=PowerFlow_Site_P_Akku:W capacity=7680&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bemerkungen:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
- strings=none sowie die Schlüssel ac2cd und dc2ac sind typisch für einen Batterie-WR bzw. kennzeichnen einen WR als Batterie-Wechselrichter &amp;lt;br&amp;gt;&lt;br /&gt;
- die an die Batterie abgegebene Leistung ist negativ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Einbindung eines Fronius Symo GEN24 10.0 Plus mit BYD Batterie ohne (virtuellen) Batterie-Wechselrichter =====&lt;br /&gt;
Diee Implementierung ist komplett auf der Seite [[Solaranlage Komplettbeispiel Fronius BYD]] beschrieben.&lt;br /&gt;
&lt;br /&gt;
Zur Integration des &#039;&#039;Fronius Symo&#039;&#039; in FHEM wird das Modul &#039;&#039;fronius.pm&#039;&#039; verwendet und in dem definierten Device &#039;&#039;Fronius_Symo_Gen24&#039;&#039; diverse userReadings erzeugt. Diese Readings werden in den korrespondierenden Schlüsseln des Attributes &#039;&#039;setupInverterDev01&#039;&#039; angegeben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setupInverterDev01 Fronius_Symo_Gen24 etotal=User_Produced_PV_Energie:kWh pvOut=PowerFlow_Site_P_PV:W capacity=6000 strings=Dach_Ost,Dach_West&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Am Wechselrichter Fronius Symo Gen24 ist eine BYD Batterie angeschlossen. Das Device &#039;&#039;PV-Batterie&#039;&#039; wird per [[ModbusAttr]] angelegt und gemanaged. Die entsprechenden Readings werden im Attribut &#039;&#039;SetupBatteryDev01&#039;&#039; hinterlegt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PV_Batterie&lt;br /&gt;
cap=10240&lt;br /&gt;
charge=BatteryChargePercent&lt;br /&gt;
icon=@dyn:@dyn:@dyn:@dyn&lt;br /&gt;
intotal=Summe_Ladung:Wh&lt;br /&gt;
outtotal=Summe_Entladung:Wh&lt;br /&gt;
pin=BatteryChargeWatt:W&lt;br /&gt;
pout=BatteryDischargeWatt:W&lt;br /&gt;
pinmax=10000&lt;br /&gt;
show=2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Einbindung eines SMA - Hybrid Sunny Tripower Smart Energy  =====&lt;br /&gt;
[[Datei:Screenshot 2025-10-05 083530.png|right|thumb|400px|SMAInverter.pm]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der genannte Wechselrichter wird über das Modul SMAInverter.pm in FHEM integriert. Die nebenstehende Abbildung zeigt und benennt die einzelnen Readings des Moduls welche in den entsprechenden Schlüsseln der SolarForecast Attribute &#039;&#039;setupInverterDevXX&#039;&#039; und &#039;&#039;setupBatteryDevXX&#039;&#039; zugeordnet werden. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Readings des SMAInverter Moduls können vor der Verwendung über geeignete Methoden (userReadings) in Readings mit sprechenden Namen überführt werden um sie mit diesen Namen in die genannten Attributschlüssel einzufügen. In der vorliegenden Lösung befinden sich die  Anwendungen SolarForecast und und die Inverter-Steuerung jeweils auf unterschiedlicher Hardware. Als Verbindungslayer wird MQTT genutzt, wobei dadurch bereits die dargestellten Readingnamen entstehen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Einbindung und Visualisierung von Umweltdaten ===&lt;br /&gt;
&lt;br /&gt;
Im Attribut &#039;&#039;&#039;setupEnvironment&#039;&#039;&#039; werden &#039;&#039;Schlüssel=Wert&#039;&#039; Paare definiert, die zur Erfassung von Umwelt- und Umfeldfaktoren dienen, die im Kontext des Moduleinsatzes und Prognosen wichtig oder hilfreich sind.&lt;br /&gt;
&lt;br /&gt;
;gridStatus: Eine &amp;lt;Gerät&amp;gt;:&amp;lt;Reading&amp;gt;:&amp;lt;Regex&amp;gt; Kombination für den Verbindungsstatus zum öffentlichen Netz. Der angegebene reguläre Ausdruck muß Boolean &#039;true&#039; für den Status &#039;Netz verfügbar/verbunden&#039; ergeben, sonst &#039;false&#039;.&lt;br /&gt;
	&lt;br /&gt;
;outsideTemp: Eine &amp;lt;Gerät&amp;gt;:&amp;lt;Reading&amp;gt; Kombination, die die aktuell gemessene Außentemperatur in °C liefert.&lt;br /&gt;
	&lt;br /&gt;
;presence: Eine &amp;lt;Gerät&amp;gt;:&amp;lt;Reading&amp;gt;:&amp;lt;Regex&amp;gt; Kombination, die den Anwesenheitsstatus der Bewohner liefert. Der angegebene reguläre Ausdruck muß Boolean &#039;true&#039; für den Status &#039;Anwesenheit&#039; ergeben, sonst &#039;false&#039;.&lt;br /&gt;
	&lt;br /&gt;
;windSpeed: Eine &amp;lt;Gerät&amp;gt;:&amp;lt;Reading&amp;gt; Kombination, die die aktuell gemessene Windgeschwindigkeit in m/s liefert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit dem Attribut und Schlüssel &#039;&#039;&#039;graphicControl-&amp;gt;headerShowEnv&#039;&#039;&#039; können diese Daten im Grafikkopf visualisiert werden. Bestimmte Ummweltdaten sind die Prognosefunktionen relevant und werden bei Bedarf aufbereitet und gespeichert. Siehe dazu auch den Abschnitt [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Integration_von_Umwelt-_und_Kontextfaktoren_in_die_Prognose|&amp;quot;Integration von Umwelt- und Kontextfaktoren in die Prognose&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Erkennung Netzausfall (öffentliches Netz)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Mit der Einbindung einer geeigneten &amp;lt;Device&amp;gt;:&amp;lt;Reading&amp;gt; Kombination im Schlüssel &#039;&#039;gridStatus&#039;&#039; erfasst SolarForecast die Verbindung zum öffentlichen Stromnetz. Der Verbindungsstatus des Netzes kann im Grafikkopf mit &#039;&#039;&#039;graphicControl-&amp;gt;headerShowEnv=gridStatus&#039;&#039;&#039; neben weiteren Informationen visualisiert werden. Die Erfassung des aktuellen Netzverbindungsstatus ist eine reine Information für den Anwender.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Der integrierte SolarForecast Grafikbereich ==&lt;br /&gt;
Das SolarForecast Modul beinhaltet eine Grafikdarstellung die sich in mehrere Bereiche gliedert. Diese Bereiche können über Attribute ein- bzw. ausgeblendet sowie die Inhalte festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2024-09-21 223545.png|right|thumb|400px|Bereiche der integrierten Grafik]]&lt;br /&gt;
&lt;br /&gt;
Der nebenstehende Screenshot gibt die Gliederung der Grafikbereiche wieder:&lt;br /&gt;
&lt;br /&gt;
 1 - der Kopfbereich (Graphic Header)&lt;br /&gt;
 2 - durch den Nutzer selbst definierbarer Inhalt (Graphic Header Own Specification) als Teil des Kopfbereiches&lt;br /&gt;
 3 - Bereich Verbraucherdarstellung (Consumer Legend)&lt;br /&gt;
 4 - Bereich Balkengrafik (Beam Graphic)&lt;br /&gt;
 5 - Energieflußgrafik (Flow Graphic)&lt;br /&gt;
&lt;br /&gt;
Jeder dieser Bereiche hat spezifische Steuerungsattribute zur Anpassung des Verhaltens und ggf. des Inhalts.&lt;br /&gt;
&lt;br /&gt;
=== 1 - Der Grafik Kopfbereich ===&lt;br /&gt;
Im Kopfbereich befinden sich fest verankerte Informationen zur verwendeten Vorhersage-API sowie deren Status, Informationen zum Sonnenaufgang und Sonnenuntergang, dem aktuellen Gesamtstatus des SolarForecast Devices, Abweichungskennzahlen der PV Vorhersage sowie weitere Kennzeichen zur Verfügung.&lt;br /&gt;
Über zwei Drucktasten kann eine Anlagenprüfung durchgeführt und in den Spportthread des Moduls im FHEM Forum abgesprungen werden.&lt;br /&gt;
&lt;br /&gt;
Mit dem Attribut &#039;&#039;&#039;graphicHeaderShow&#039;&#039;&#039; kann der gesamte Kopfbereich 1 und 2 (nutzereigener Teilbereich) ausgeblendet werden. Wird der Kopbereich ausgeblendet, ist es hilfreich mit dem Attribut &#039;&#039;&#039;plantControl-&amp;gt;showLink&#039;&#039;&#039; einen Link zur Detailgrafik einzufügen da der in der Kopfgrafik integrierte Link in diesem Fall nicht mehr zur Verfügung steht. &lt;br /&gt;
&lt;br /&gt;
Das Attribut &#039;&#039;&#039;graphicHeaderDetail&#039;&#039;&#039; definiert welche Bereiche des Grafikkopfes angezeigt werden sollen. Es kann die Anzeige des Energieverbrauches, der PV-Erzeugung und der vom Nutzer selbst definierte Inhalt miteinander frei kombiniert werden.&lt;br /&gt;
&lt;br /&gt;
=== 2 - Der Bereich mit selbst definierbarem Inhalt (Graphic Header Own Specification) ===&lt;br /&gt;
In diesem Bereich kann der User beliebige Readings, Set-Kommandos und Attribute des SolarForecast Devices oder anderer Devices, die sich im gleichen FHEM-System wie das SolarForecast Device befinden, anzeigen lassen.&lt;br /&gt;
&lt;br /&gt;
Dieser Bereich ist als Tabelle mit einer beliebigen Anzahl von Zeilen organisiert. Jede Zeile beinhaltet ein Kommentarfeld und vier Nutzfelder zur Darstellung ausgewähler Werte + Label. Der Bereich bzw. der Inhalt des Bereiches wird mit dem Attribut &#039;&#039;&#039;graphicHeaderOwnspec&#039;&#039;&#039; definiert.  &lt;br /&gt;
&lt;br /&gt;
Das nachfolgende Beispiel zeigt ein real gesetztes graphicHeaderOwnspec Attribut. Die Leerzeilen sind nicht notwendig, erhöhen aber die Lesbarkeit der Struktur.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
Autarkierate:Current_AutarkyRate&lt;br /&gt;
PV&amp;amp;nbsp;übermorgen:special_dayAfterTomorrowPVforecast&lt;br /&gt;
Verbrauch&amp;amp;nbsp;bis&amp;lt;br&amp;gt;Sunset:special_todayConForecastTillSunset&lt;br /&gt;
Verbrauch&amp;amp;nbsp;bis&amp;lt;br&amp;gt;nächsten&amp;amp;nbsp;Sunrise:special_conForecastTillNextSunrise&lt;br /&gt;
&lt;br /&gt;
#Batterie&lt;br /&gt;
BatteryLive&amp;amp;nbsp;Status:userFn_BatLive_State&lt;br /&gt;
SoC&amp;amp;nbsp;Limit:Settings_CGwacs_BatteryLife_MinimumSocLimit_value@MQTT2_cerboGX_c0619ab34e08_settings&lt;br /&gt;
SoC&amp;amp;nbsp;Ist:SOC_value@MQTT2_cerboGX_c0619ab34e08_battery&lt;br /&gt;
SOC&amp;amp;nbsp;Optimum:Battery_OptimumTargetSoC&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
aktuelle&amp;amp;nbsp;Ladung:userFn_Bat_EnergyState&lt;br /&gt;
Verfügbar:userFn_BatLive_UsableEnergy&lt;br /&gt;
benötigte&amp;amp;nbsp;Ladeenergie:userFn_Bat_EnergyRemain&lt;br /&gt;
Ladefreigabe:Battery_ChargeRecommended&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
akt.&amp;amp;nbsp;DC&amp;amp;nbsp;Strom:DC_Current_value@MQTT2_cerboGX_c0619ab34e08_battery&lt;br /&gt;
Restladezeit&amp;amp;nbsp;Ziel:userFn_Bat_HoursUntilChargeFinish&lt;br /&gt;
MPII&amp;amp;nbsp;Ladestrom&amp;lt;br&amp;gt;Limit&amp;amp;nbsp;Soll:userFn_Bat_MaxChargeCurrent_set&lt;br /&gt;
:&lt;br /&gt;
&lt;br /&gt;
#Settings&lt;br /&gt;
Batterie&amp;amp;nbsp;Lademanagement:userFn_BatteryChargeManagement&lt;br /&gt;
SoC&amp;amp;nbsp;Management:userFn_BatterySoCManagement&lt;br /&gt;
MPII&amp;amp;nbsp;Ladestrom&amp;lt;br&amp;gt;Limit&amp;amp;nbsp;Ist:MaxChargeCurrent@MQTT2_cerboGX_c0619ab34e08_vebus&lt;br /&gt;
SmartSolar&amp;lt;br&amp;gt;Einspeisung:OvervoltageFeedIn@MQTT2_cerboGX_c0619ab34e08_settings&lt;br /&gt;
&lt;br /&gt;
MPII&amp;amp;nbsp;Limit&amp;lt;br&amp;gt;Einspeisung&amp;amp;nbsp;(W):MaxFeedInPower@MQTT2_cerboGX_c0619ab34e08_settings&lt;br /&gt;
SOC&amp;amp;nbsp;Limit&amp;amp;nbsp;Soll:MinimumSocLimit@MQTT2_cerboGX_c0619ab34e08_settings&lt;br /&gt;
Verbr.&amp;amp;nbsp;Neuplanung:consumerNewPlanning&lt;br /&gt;
Wetteranzeige:graphicShowWeather &lt;br /&gt;
&lt;br /&gt;
Anzeige&amp;amp;nbsp;Nachtstunden:graphicShowNight&lt;br /&gt;
hist.&amp;amp;nbsp;Stunden:graphicHistoryHour&lt;br /&gt;
Autokorrektur:pvCorrectionFactor_Auto&lt;br /&gt;
Victron&amp;amp;nbsp;BatteryLife&amp;lt;br&amp;gt;(1=an,10=aus):BatteryLife@MQTT2_cerboGX_c0619ab34e08_settings&lt;br /&gt;
&lt;br /&gt;
Grid&amp;amp;nbsp;Setpoint:GridSetpoint@MQTT2_cerboGX_c0619ab34e08_settings&lt;br /&gt;
Debug:ctrlDebu&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommentarfeld am Beginn einer Zeile wird durch ein &#039;&#039;&#039;#&#039;&#039;&#039; gekennzeichnet. Folgt dem # ein String, wird dieser String als Kommentarangabe gewertet und in der Grafik ausgegeben. Ein leeres Kommentarfeld wird lediglich durch ein # gefolgt von einem Leerzeichen oder NL beschrieben:&lt;br /&gt;
&lt;br /&gt;
 #:&amp;lt;Text&amp;gt;  (bzw nur # für einen &#039;leeren&#039; Titel)&lt;br /&gt;
&lt;br /&gt;
Ein Netzfeld bzw. ein Datensatz wird durch die Angabe von einem Label und dem darzustellenden Wert getrennt durch &#039;:&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Label&amp;gt;:&amp;lt;Reading, Attribut oder Set-Kommando&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das System erkennt selbständig, ob es sich bei der Angabe um ein Reading, Attribut oder ein Set-Kommando handelt. Sollen Readings, Set-Kommandos und Attribute anderer Devices als dem SolarForecast-Device angezeigt werden, kann dies einfach durch Zusatz von&lt;br /&gt;
&lt;br /&gt;
 ....@&amp;lt;Device-Name&amp;gt;&lt;br /&gt;
&lt;br /&gt;
an den Parameter erreicht werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2024-12-05 203916.png|right|thumb|400px|Darstellung eigener Grafikbereich]]&lt;br /&gt;
Die Eingabe kann mehrzeilig erfolgen. Werte mit den Einheiten &amp;quot;Wh&amp;quot; bzw. &amp;quot;kWh&amp;quot; werden entsprechend der Einstellung des Attributs &#039;&#039;&#039;graphicEnergyUnit&#039;&#039;&#039; umgerechnet. Im Label sind Leerzeichen durch &amp;quot;&amp;amp;amp;nbsp;&amp;quot; einzufügen, ein Zeilenumbruch durch &amp;quot;&amp;amp;lt;br&amp;amp;gt;&amp;quot;. Ein leeres Feld in einer Zeile wird durch &amp;quot;:&amp;quot; ohne eine weitere Angabe erzeugt.&lt;br /&gt;
&lt;br /&gt;
Die nebenstehende Abbildung zeigt die reale Darstellung der oben angegebenen Struktur im Attribut graphicHeaderOwnspec.&lt;br /&gt;
&lt;br /&gt;
==== Formatierung der Inhalte im Bereich &amp;quot;Graphic Header Own Specification&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
Die angezeigten Inhalte, wie z.B. Readingwerte, des User eigenen Bereiches (Attribut graphicHeaderOwnspec) können durch Spezifikationen im Attribut &#039;&#039;&#039;graphicHeaderOwnspecValForm&#039;&#039;&#039; manipuliert werden.&lt;br /&gt;
&lt;br /&gt;
Die Online-Hilfe zum Attribut graphicHeaderOwnspecValForm erläutert die verfügbaren Möglichkeiten und Optionen.&lt;br /&gt;
Als Beispiel hier einige mögliche Notationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &#039;userFn_Bat_HoursUntilChargeFinish&#039;                        =&amp;gt; &amp;quot;($VALUE).&#039; Stunden&#039;&amp;quot;,&lt;br /&gt;
  &#039;MQTT2_cerboGX_c0619ab34e08_battery.SOC_value&#039;             =&amp;gt; &amp;quot;%.1f %%&amp;quot;,&lt;br /&gt;
  &#039;Settings_CGwacs_BatteryLife_MinimumSocLimit_value&#039;        =&amp;gt; &amp;quot;%.1f %%&amp;quot;,&lt;br /&gt;
  &#039;Info_MaxChargeCurrent_value&#039;                              =&amp;gt; &amp;quot;($VALUE).&#039; A&#039;&amp;quot;,&lt;br /&gt;
  &#039;DC_Current_value&#039;                                         =&amp;gt; &amp;quot;%.0f A&amp;quot;,&lt;br /&gt;
  &#039;MQTT2_cerboGX_c0619ab34e08_solarcharger_Common.Regulated&#039; =&amp;gt; &amp;quot;($VALUE eq &#039;1&#039; ? &#039;Ja&#039; : &#039;Nein&#039;)&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Besonderheit besteht bei darzustellenden Werten die die Einheiten &#039;Wh&#039; bzw. &#039;kWh&#039; besitzen. Diese Werte und Einheiten werden automatisch entsprechend des gesetzten Attributes graphicEnergyUnit umgerechnet und angezeigt.&lt;br /&gt;
&lt;br /&gt;
Soll in diesen Fällen eine automatische Formatierung umgangen werden, kann eine solche Notation verwendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &#039;Today_PVforecast&#039; =&amp;gt; &amp;quot;(sprintf &#039;%.1f &amp;amp;amp;nbsp;kWh&#039;, ($VALUE / 1000))&amp;quot;,&lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/pre&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Die Angabe von &amp;amp;amp;nbsp; vor &#039;kWh&#039; verhindert die Erkennung der Einheit und so auch die automatische Umsetzung durch das Modul. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 3 - Bereich Verbraucherdarstellung (Consumer Legend) ===&lt;br /&gt;
Dieser Grafikbereich zeigt die im Modul registrierten Verbraucher sowie deren Status und weitere Informationen an. Sind die Voraussetzungen gegeben, d.h. entsprechende Schlüssel in der ConsumerXX-Attributen gesetzt, können die Verbraucher über das Paneel manuell geschaltet werden.&lt;br /&gt;
&lt;br /&gt;
Zur Anpassung der Darstellung sind verschiedene Attribute verfügbar:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;consumerControl-&amp;gt;showLegend: Definiert die Lage bzw. Darstellungsweise der Verbraucherlegende sofern Verbraucher im SolarForecast Device registriert sind.&lt;br /&gt;
;consumerControl-&amp;gt;adviceIcon: Definiert die Art der Information über die geplanten Schaltzeiten eines Verbrauchers in der Verbraucherlegende. &lt;br /&gt;
;consumerControl-&amp;gt;detailLink: Wenn gesetzt, ist der jeweilige Verbraucher klickbar um direkt zur Detailansicht des jeweiligen Geräts auf einer neuen Browserseite zu gelangen. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Im Standard wird das Verbraucherpaneel zwischen dem Kopfbereich und der ersten Balkengrafik Ebene dargestellt. Mit dem Attribut &#039;&#039;&#039;consumerControl-&amp;gt;showLegend&#039;&#039;&#039; und Argument &#039;&#039;&#039;icon_bottom&#039;&#039;&#039; oder &#039;&#039;&#039;text_bottom&#039;&#039;&#039; kann das Verbraucherpaneel an das Ende des Grafikbereiches verschoben werden.&lt;br /&gt;
Die Verwendung von &#039;&#039;&#039;text_bottom&#039;&#039;&#039; oder &#039;&#039;&#039;text_top&#039;&#039;&#039; blendet die Icon-Spalte im Verbraucherpaneel aus.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Screenshot 2025-02-08 093239.png|Darstellung mit consumerControl showLegend=icon_top (default)&lt;br /&gt;
File:Screenshot 2025-02-08 093646.png|Darstellung mit consumerControl showLegend=icon_bottom&lt;br /&gt;
File:Screenshot 2025-02-08 152018.png|Darstellung mit consumerControl showLegend=text_top bzw. text_bottom&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2025-02-08 213634.png|right|thumb|400px|]]&lt;br /&gt;
Ein Mouse-Over über das Uhrensymbol zeigt nähere Informationen zum Status, den Planungsdaten, Modus und weitere Daten des Verbrauchers. Der Schalter &amp;quot;Aus/Ein&amp;quot; visualisiert den Schaltzustand des Verbrauchers und können auch zum manuellen Schalten des Verbrauchers dienen. Voraussetzung ist, dass im consumer-Attribut die Schlüssel &amp;quot;on&amp;quot; und &amp;quot;off&amp;quot; mit den Set-Kommandos zum Schalten des Verbrauchers defininiert sind.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2025-02-08 222210.png|right|thumb|300px|]]&lt;br /&gt;
Der Auto-Schieberegler zeigt einerseits den Freigabestatus zum Schalten des Verbrauchers durch das SolarForecast Modul und kann andererseits manuell betätigt werden. Der Status des Reglers korrespondiert mit dem im zugehörigen Consumer Attribut vorhandenen Schlüssel &#039;&#039;&#039;auto&#039;&#039;&#039; angegebenen Reading-Wert.&lt;br /&gt;
&lt;br /&gt;
Die Verbraucherbezeichnungen in dem Paneel können in der Standardkonfiguration angeklickt werden um direkt zur Detailansicht des Devices zu gelangen. Mit dem Attribut &#039;&#039;&#039;consumerControl-&amp;gt;detailLink&#039;&#039;&#039; kann der Link zur Detailansicht deaktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Das Uhrensymbol kann mit dem Attribut &#039;&#039;&#039;consumerControl-&amp;gt;adviceIcon&#039;&#039;&#039; geändert und/oder dessen Farbe angepasst, sowie einen Informationstext statt eines Icons angezeigt werden. &lt;br /&gt;
&lt;br /&gt;
=== 4 - Bereich Balkengrafik (Beam Graphic) ===&lt;br /&gt;
&lt;br /&gt;
Die Balkengrafik des Moduls ist ein wesentliches Visualisierungshilfsmittel. Im Auslieferungszustand existiert eine Balkengrafikebene, die &#039;&#039;&#039;Ebene 1&#039;&#039;&#039;.&lt;br /&gt;
Jede Ebene kann zwei Balkendiagramme mit auswählbaren Inhalten, Farben und einstellbarem LayoutTyp darstellen. In Ebene 1 kann die Wettervorhersage eingebettet oder, bei Vorhandensein von Batteriegeräten, die zukünftigen Zeiten mit empfohlener Ladefreigabe und SoC-Prognose eingeblendet werden. &lt;br /&gt;
&lt;br /&gt;
Welche Daten in welchen Zeiträumen dargestellt werden sollen, die Bestimmung des Layouts, die Gestaltung der Balken und einiges mehr wird durch Attribute gesteuert. Ein Teil dieser Einstellungen wird über das zusammengesetzete Attribut &#039;&#039;&#039;graphicControl-&amp;gt;&#039;Schlüssel&#039;=&#039;Wert&#039;&#039;&#039;&#039; eingestellt:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::*&#039;&#039;&#039;grundsätzliche Layout Definitionen&#039;&#039;&#039;&lt;br /&gt;
[[Datei:Screenshot 2025-01-12 204342.png|right|thumb|400px|Standardanzeige mit Wetter-Icons, gesetzen Attributen graphicBeam1Color=D4C177, graphicHistoryHour=11]]&lt;br /&gt;
&lt;br /&gt;
;graphicControl-&amp;gt;beamHeightlevel:Faktor zur Berechnung der Höhenverhältnisse der jeweiligen Ebene (siehe auch diesen [[#Wirkung_von_graphicControl-&amp;gt;beamHeightlevel_auf_die_Zonen_(z1_bis_z3)_je_nach_layoutType|Abschnitt]]). &lt;br /&gt;
;graphicControl-&amp;gt;beamPaddingTop:Legt den Platz in px im Balkendiagramm fest, der zwischen dem oberen Rand der jeweiligen Balkengrafik Ebene und der ersten Text- oder Iconreihe dieser Ebene eingefügt wird.&lt;br /&gt;
;graphicControl-&amp;gt;beamPaddingBottom:Legt den Platz in px im Balkendiagramm fest, der zwischen der letzten Text- oder Iconreihe der jeweiligen Balkengrafik Ebene und dem unteren Rand dieser Ebene eingefügt wird. &lt;br /&gt;
;graphicControl-&amp;gt;layoutType:Layout-Optionen zur grundlegenden Gestaltung der Balkengrafik&lt;br /&gt;
;graphicControl-&amp;gt;hourStyle:Format der Zeitangabe in der Balkengrafik&lt;br /&gt;
;graphicControl-&amp;gt;hourCount:Anzahl der darzustellenden Balken/Stunden in der Balkengrafk&lt;br /&gt;
[[Datei:Screenshot Screenshot 2025-05-21 153613.png|right|thumb|400px|Erweiterung des oberen und unteren Abstandes mit den Attributen graphicControl-&amp;gt;beamPaddingTop und graphicControl-&amp;gt;beamPaddingBottom]]&lt;br /&gt;
;graphicControl-&amp;gt;energyUnit:definiert die Einheit zur Anzeige der elektrischen Leistung in der Grafik&lt;br /&gt;
;graphicHistoryHour:Anzahl der vorangegangenen Stunden die in der Balkengrafik dargestellt werden&lt;br /&gt;
;graphicControl-&amp;gt;beamWidth:Vorgabe Breite der Balken der Balkengrafik in px (sonst automatische Bestimmung)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::*&#039;&#039;&#039;Definition der Inhalte und Balkeneigenschaften&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2025-01-12 204756.png|right|thumb|400px|Wie oben aber mit gesetzem Attribut graphicShowNight=1]]&lt;br /&gt;
;graphicBeam1Color:Farbauswahl des primären Balkens (Ebene 1)&lt;br /&gt;
;graphicBeam2Color:Farbauswahl des sekundären Balkens (Ebene 1)&lt;br /&gt;
;graphicBeam1Content:Legt den darzustellenden Inhalt des primären Balken fest (Ebene 1)&lt;br /&gt;
;graphicBeam2Content:Legt den darzustellenden Inhalt des sekundären Balken fest (Ebene 1)&lt;br /&gt;
;graphicBeam1FontColor:Auswahl der Schriftfarbe des primären Balkens (Ebene 1)&lt;br /&gt;
;graphicBeam2FontColor:Auswahl der Schriftfarbe des sekundären Balkens (Ebene 1)&lt;br /&gt;
[[Datei:Screenshot 2025-01-12 205024.png|right|thumb|400px|Balkengrafik mit aktivierter Ebene 2, gesetzem Attribut graphicShowNight=0 (ohne Zeitsynchronisation zwischen Ebene 1 und Ebene 2)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::*&#039;&#039;&#039;zusätzliche Optionen&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
;graphicShowNight:Anzeigen oder Verbergen der Nachtstunden in der Balkengrafik&lt;br /&gt;
;graphicShowWeather:Wettericons in der Balkengrafik anzeigen/verbergen (nur Ebene 1)&lt;br /&gt;
;graphicWeatherColor:Farbe der Wetter-Icons für die Tagesstunden&lt;br /&gt;
;graphicWeatherColorNight:Farbe der Wetter-Icons für die Nachtstunden&lt;br /&gt;
;graphicShowDiff:Zusätzliche Anzeige der Differenz &amp;quot;&amp;lt;primärer Balkeninhalt&amp;gt; - &amp;lt;sekundärer Balkeninhalt&amp;gt;&amp;quot; im Kopf- oder Fußbereich der Balkengrafik&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die genaue Beschreibung und deren Optionen sind der aktuellen Online-Hilfe zu entnehmen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Für alle Ebenen gilt:&#039;&#039;&#039; Ein Attribut mit einer ungeraden Balkennummer (z.B. graphicBeam1Content) bezieht sich immer auf den primären Balken, ein Attribut mit einer geraden Balkennummer (z.B. graphicBeam2Content) bezieht sich immer auf den sekundären Balken.&lt;br /&gt;
&lt;br /&gt;
Die Balken haben, wie die meisten Elemente in der Balkengrafik, eine Mouse-Over Eigenschaft welche relevante Informationen zu den dargestellten Werten anzeigt. &lt;br /&gt;
&lt;br /&gt;
Sind die Nachtunden mit &#039;&#039;&#039;graphicShowNight&#039;&#039;&#039; ausgeblendet, werden keine Balken angezeigt sofern es keine Werte anzuzeigen gibt. Sollten dennoch Werte ungleich 0 anzuzeigen sein, werden diese Werte auch trotz ausgeblendeter Nachstunden angezeigt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Aktivierung der Balkengrafik Ebene 2 ====&lt;br /&gt;
[[Datei:Screenshot 2025-01-12 211741.png|right|thumb|400px|Balkengrafik mit aktivierter Ebene 2, gesetzem Attribut graphicShowNight=01 (mit Zeitsynchronisation zwischen Ebene 1 und Ebene 2)]]&lt;br /&gt;
&lt;br /&gt;
Um die &#039;&#039;&#039;Ebene 2&#039;&#039;&#039; der Balkengrafik zu aktivieren, setzt man das Attribut &#039;&#039;&#039;graphicBeam3Content&#039;&#039;&#039; und/oder &#039;&#039;&#039;graphicBeam4Content&#039;&#039;&#039; mit den gewünschten darzustellenden Inhalten. Die weiteren Darstellungsoptionen, wie graphicBeamCColor, können ebenfalls für den jeweiligen Balken selektiv definiert werden wenn ein Attribut mit der entsprechenden Nummer (z.B. 4 für Balken 4) vorhanden ist. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Die Wetter-Icons können nur in Ebene 1 integriert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Werden in der Balkengrafik die Nachtstunden ausgeblendet (&#039;&#039;&#039;graphicShowNight=0&#039;&#039;&#039; bzw. default), findet zwischen der Ebene 1 und der Ebene 2 keine Synchronisation der Zeitebene statt. Falls es einen inhaltlichen Zusammenhang zwischen den Werten der Ebene 1 und Ebene 2 gibt, eine Zeitsynchronisation zwischen den Ebenen wünschenswert und sinnvoll. Durch Setzen des Attrbut &#039;&#039;&#039;graphicShowNight=01&#039;&#039;&#039; kann diese Synchronisation eingeschaltet werden. &lt;br /&gt;
&lt;br /&gt;
Dabei ist die Ebene 1 die führende Ebene, d.h. diese Ebene vererbt die exkludierten bzw. eventuell inkludierten Nachtstunden (wenn Werte in den Balken der Ebene 1 angezeigt werden sollen) an die nachfolgende Ebene.&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
==== Aktivierung der Balkengrafik Ebene 3 ====&lt;br /&gt;
&lt;br /&gt;
Um die &#039;&#039;&#039;Ebene 3&#039;&#039;&#039; der Balkengrafik zu aktivieren, setzt man das Attribut &#039;&#039;&#039;graphicBeam5Content&#039;&#039;&#039; und/oder &#039;&#039;&#039;graphicBeam6Content&#039;&#039;&#039; mit den gewünschten darzustellenden Inhalten. Die weiteren Darstellungsoptionen, wie graphicBeamCColor, können ebenfalls für den jeweiligen Balken selektiv definiert werden wenn ein Attribut mit der entsprechenden Nummer (z.B. 5 für Balken 5) vorhanden ist. &lt;br /&gt;
&lt;br /&gt;
Werden in der Balkengrafik die Nachtstunden ausgeblendet (&#039;&#039;&#039;graphicShowNight=0&#039;&#039;&#039; bzw. default), findet zwischen der Ebene 1 und der Ebene 3 keine Synchronisation der Zeitebene statt. Falls es einen inhaltlichen Zusammenhang zwischen den Werten der Ebene 1 und Ebene 3 gibt, ist eine Zeitsynchronisation zwischen den Ebenen wünschenswert und sinnvoll. Durch Setzen des Attrbut &#039;&#039;&#039;graphicShowNight=01&#039;&#039;&#039; kann diese Synchronisation eingeschaltet werden. &lt;br /&gt;
&lt;br /&gt;
Dabei ist die Ebene 1 die führende Ebene, d.h. diese Ebene vererbt die exkludierten bzw. eventuell inkludierten Nachtstunden (wenn Werte in den Balken der Ebene 1 angezeigt werden sollen) an die nachfolgenden Ebenen, d.h. auch auf die Ebene 3.&lt;br /&gt;
&lt;br /&gt;
  &lt;br /&gt;
==== Wirkung von graphicControl-&amp;gt;beamHeightlevel auf die Zonen (z1 bis z3) je nach layoutType ====&lt;br /&gt;
&lt;br /&gt;
🎯 &#039;&#039;&#039;Grundprinzip&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jede der verfügbaren Ebenen ist in Zonen aufgeteilt. Die Wirkung und der Einsatz der Zonen ist vom verwendeten &#039;&#039;graphicControl-&amp;gt;layoutType&#039;&#039; abhängig. &amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;graphicControl-&amp;gt;beamHeightlevel&#039;&#039; ist ein &#039;&#039;&#039;Skalierungsfaktor&#039;&#039;&#039;, der verwendet wird um für jede Zone die &#039;&#039;&#039;resultierende Zonenhöhe (px)&#039;&#039;&#039; zu berechnen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
𝑝𝑥 = 𝑔𝑟𝑜𝑢𝑛𝑑 + (𝑣𝑎𝑙 / 𝑚𝑎𝑥𝑉𝑎𝑙) ⋅ (𝑏𝑒𝑎𝑚𝐻𝑒𝑖𝑔ℎ𝑡𝑙𝑒𝑣𝑒𝑙 − 𝑔𝑟𝑜𝑢𝑛𝑑)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das bedeutet:&lt;br /&gt;
* beamHeightlevel bestimmt die &#039;&#039;&#039;maximale mögliche Höhe&#039;&#039;&#039;, die ein Balken erreichen kann,&lt;br /&gt;
* aber die tatsächliche Höhe hängt &#039;&#039;&#039;immer&#039;&#039;&#039; vom Verhältnis val / maxVal und vom scaleMode ab.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🧩 &#039;&#039;&#039;Zonenmodell (z1–z3)&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unabhängig vom layoutType besteht jede Balkenebene (z.Zt. Ebene 1 bis 3) aus Zonen, die übereinander angeordnet sind:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Zone !! Bedeutung !! Sichtbare Wirkung&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;z1&#039;&#039;&#039; || Freiraum über dem Balken (Abstand, Zahlen, Icons) || Abstand nach oben&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;z2&#039;&#039;&#039; || Balken mit dem höchsten positiven Wert oder oberer Teil eines Stapels || sichtbarer höherer (primärer) Balken&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;z3&#039;&#039;&#039; || Balken mit dem niedrigeren positiven Wert double/staple oder negativer Bereich (diff) || kleinerer (sekundärer) Balken oder negativer Balken&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Summe aus z1 + z2 + z3 ergibt die &#039;&#039;&#039;Gesamthöhe&#039;&#039;&#039;, die durch &#039;&#039;beamHeightlevel&#039;&#039; &#039;&#039;&#039;skaliert&#039;&#039;&#039;, aber nicht fest vorgegeben wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🧩 &#039;&#039;&#039;Wirkung pro layoutType&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Datei:Zonenskizze.png|right|thumb|400px|Zonenskizze]]&lt;br /&gt;
🟦 &#039;&#039;&#039;layoutType = single&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zonen:&lt;br /&gt;
* z1 = Freiraum&lt;br /&gt;
* z2 = Balken (beam1)&lt;br /&gt;
* z3 = nicht genutzt&lt;br /&gt;
&lt;br /&gt;
Wirkung von &#039;&#039;beamHeightlevel&#039;&#039;:&lt;br /&gt;
* skaliert die Gesamthöhe von z1 + z2&lt;br /&gt;
* z2 wächst proportional zu &#039;&#039;val / maxVal&#039;&#039;&lt;br /&gt;
* z1 ist der verbleibende Rest&lt;br /&gt;
* kleine Werte können bei linearer Skalierung sehr klein werden&lt;br /&gt;
* &#039;&#039;scaleMode=log&#039;&#039; macht kleine Werte sichtbar größer&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🟩 &#039;&#039;&#039;layoutType = double&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zonen:&lt;br /&gt;
* z1 = Freiraum&lt;br /&gt;
* z2 = größerer Wert (beam1 oder beam2)&lt;br /&gt;
* z3 = kleinerer Wert oder Stapelanteil&lt;br /&gt;
&lt;br /&gt;
Wirkung von &#039;&#039;beamHeightlevel&#039;&#039;:&lt;br /&gt;
* skaliert die Gesamthöhe des Balkenpaares&lt;br /&gt;
* z2 und z3 teilen sich die Höhe proportional&lt;br /&gt;
* bei großen Wertunterschieden wird z3 sehr dünn&lt;br /&gt;
* bei &#039;&#039;scaleMode=staple&#039;&#039; werden beide Werte übereinander gestapelt&lt;br /&gt;
* bei &#039;&#039;scaleMode=log&#039;&#039; werden Unterschiede geglättet&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🟥 &#039;&#039;&#039;layoutType = diff&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zonen:&lt;br /&gt;
* z1 = positiver Freiraum&lt;br /&gt;
* z2 = positiver Balken (falls diff &amp;gt; 0)&lt;br /&gt;
* z3 = negativer Balken (falls diff &amp;lt; 0) &amp;lt;br&amp;gt;Hinweis: technisch existiert auch z4 als Freiraum unterhalb, aber visuell Teil von z3&lt;br /&gt;
&lt;br /&gt;
Wirkung von &#039;&#039;beamHeightlevel&#039;&#039;:&lt;br /&gt;
* skaliert die Gesamthöhe der diff‑Darstellung&lt;br /&gt;
* die Null-Linie wird &#039;&#039;&#039;dynamisch verschoben&#039;&#039;&#039;, abhängig von maxDif/minDif&lt;br /&gt;
* dadurch ändern sich die relativen Höhen von z1/z2/z3&lt;br /&gt;
* große Ausreißer verschieben die Null-Linie stark&lt;br /&gt;
* kleine Werte können optisch verschwinden&lt;br /&gt;
* &#039;&#039;scaleMode=log&#039;&#039; kann die Darstellung stabilisieren&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
⚙️ &#039;&#039;&#039;Einfluss des scaleMode&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! scaleMode !! Wirkung auf die Zonen&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;lin&#039;&#039;&#039; || z2/z3 werden proportional zu den Rohwerten skaliert → große Unterschiede sichtbar&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;log&#039;&#039;&#039; || z2/z3 werden logarithmisch gedämpft → kleine Werte werden sichtbarer&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;staple&#039;&#039;&#039; || nur für layoutType=double: z2 und z3 werden übereinander gestapelt&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;beamHeightlevel&#039;&#039; wirkt in allen Modi als &#039;&#039;&#039;Multiplikator&#039;&#039;&#039;, der die resultierenden Höhen streckt oder staucht.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 5 - Die Energieflußgrafik (Flow Graphic) ===&lt;br /&gt;
[[Datei:Screenshot 2025-02-13 213424.png|right|thumb|400px|Energieflußgrafik mit Verbrauchern in der Nachtdarstellung (Mondphasen) nach Sonnenuntergang]]&lt;br /&gt;
&lt;br /&gt;
Die Energieflußgrafik stellt die registrierten Erzeuger, Batterien, Netzzugänge und Verbraucher strukturiert in mehreren Ebenen dar:&lt;br /&gt;
&lt;br /&gt;
;Ebene 1: In der oberen Ebene befinden sich die PV-Generatoren, Smart-Loader sowie sonstigen Erzeuger &lt;br /&gt;
;Ebene 2: Die mittlere Ebene organisiert den Zugang zum öffentlichen Netz, dem Hausknoten, dem Batterieknoten sowie einem Dummy-Verbraucher (Lampensymbol) für den Energieverbrauch des Hauses der keinem der registrierten Verbraucher zugeordnet werden kann.&lt;br /&gt;
;Ebene 3: In der unteren Ebene werden die registrierten Verbraucher dargestellt. Unterhalb der Verbrauchersymbole werden der aktuelle Verbrauch (bzw. der On/Off-Zustand) sowie darunter die Restlaufzeit (Minuten) des Verbrauchers, sofern er durch das Modul geplant und gestartet wurde. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Position und Gestaltung der Grafikelemente ist umfangreich über das Attribut &#039;&#039;&#039;flowGraphicControl&#039;&#039;&#039; und den darin verfügbaren Schlüsseln einstellbar.&lt;br /&gt;
Die Bedeutung der Schlüssel ist in der Online-Hilfe zum Attribut mit einem Beispiel beschrieben. &lt;br /&gt;
&lt;br /&gt;
Darüber hinaus enthalten die Setup-Attribute &#039;&#039;&#039;setupInverterDevXX&#039;&#039;&#039;, &#039;&#039;&#039;setupOtherProducerXX&#039;&#039;&#039; und &#039;&#039;&#039;consumerXX&#039;&#039;&#039; weitere Einstellungsmöglichkeiten um deren Icons und Färbungen in der Flußgrafik individuell einstellen zu können. So sind zum Beispiel die Icons der PV-Inverter und deren Färbung mit dem Schlüssel &#039;&#039;&#039;icon&#039;&#039;&#039; der setupInverterDevXX-Attribute in Abhängigkeit von Tag und Nacht separat definierbar.&lt;br /&gt;
&lt;br /&gt;
In den Verbraucher-Attributen ist mit dem Schlüssel &#039;&#039;&#039;noshow&#039;&#039;&#039; die Sichtbarkeit in der Flußgrafik definierbar.&lt;br /&gt;
&lt;br /&gt;
Generell steuert das Attribut &#039;&#039;&#039;graphicSelect&#039;&#039;&#039; die Ein- bzw. Ausblendung der gesamten Flußgrafik.&lt;br /&gt;
&lt;br /&gt;
== Bestimmung von Sonnenaufgang und Sonnenuntergang ==&lt;br /&gt;
&lt;br /&gt;
Im Modul werden die Zeiten für den Sonnenaufgang und Sonnenuntergang aus alternativen Quellen verwendet. Es gelten dabei die folgenden Prioritäten.&lt;br /&gt;
&lt;br /&gt;
* sind die lokalen Koordinaten &#039;&#039;latitude, longitude, altitude&#039;&#039; im &#039;&#039;global&#039;&#039; Device gesetzt, erfolgt die Berechnung dieser Daten mit dem Parameter &#039;&#039;&#039;HORIZON=-0.833&#039;&#039;&#039; (vgl. CommandRef zu [https://fhem.de/commandref_DE.html#SUNRISE_EL SUNRISE_EL]). &lt;br /&gt;
&lt;br /&gt;
* sollten die lokalen Koordinaten nicht gesetzt sein, werden die Angaben aus dem in Attribut &#039;&#039;setupWeatherDev1&#039;&#039; angegebenen Wetter-Device entnommen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der Wert &#039;&#039;−0.833°&#039;&#039; entspricht dem international üblichen Standard für die Berechnung von Sonnenauf‑ und untergangszeiten. Er berücksichtigt sowohl die atmosphärische Refraktion als auch den halben Sonnendurchmesser und beschreibt damit den Moment, in dem der obere Sonnenrand scheinbar den Horizont berührt. Viele astronomische Algorithmen und [https://metacpan.org/release/JFORGET/DateTime-Event-Sunrise-0.0505/view/lib/DateTime/Event/Sunrise.pm Bibliotheken] verwenden diesen Wert als Default, weshalb er auch in SolarForecast eingesetzt wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Die Verbrauchsprognose ==&lt;br /&gt;
Im Gegensatz zu der PV Prognose gibt es keine API oder andere externen Datenquellen die für die Verbrauchsprognose herangezogen werden könnten.&lt;br /&gt;
&lt;br /&gt;
Zum Zweck der Verbrauchsermittlung verwendet das Modul die Meterdaten aus dem Attribut &#039;&#039;setupMeterDev&#039;&#039; sowie den weiteren setup-Attributen &#039;&#039;setupInverterDevXX&#039;&#039;. &lt;br /&gt;
Sind auch andere Erzeuger (BHKW, Windanlagen, etc.) bzw. eine Batterie vorhanden, sind ebenfalls die Attribute &#039;&#039;setupOtherProducerXX&#039;&#039; bzw. &#039;&#039;setupBatteryDev&#039;&#039; für die Berechnung des Hausverbrauchs relevant. In diesen Attributen gibt es die Schlüssel &#039;&#039;*total&#039;&#039; die teilweise optional sind. Für die Verbrauchsprognose bilden sie jedoch die Berechnungsgrundlage und sind deswegen für diese Funktionalität wichtig anzugeben.&lt;br /&gt;
&lt;br /&gt;
Die Verbrauchswerte werden stundengenau erfasst und im Datenspeicher &#039;&#039;pvHistory&#039;&#039; für 31 Tage, sowie im Datenspeicher &#039;&#039;pvCircular&#039;&#039; 210 Tage gespeichert. Die beiden Datenspeicher übernehmen unterschiedliche Aufgaben im Rahmen der Prognoseerstellung. Auf Grundlage der gespeicherten und somit historischen Verbrauchswerte erstellt das Modul eine Prognose für die kommende Zeit.&lt;br /&gt;
&lt;br /&gt;
Mit dem Kommando  &lt;br /&gt;
&lt;br /&gt;
    &amp;quot;get ... pvHistory [Tag]&amp;quot; &lt;br /&gt;
&lt;br /&gt;
wird der Inhalt aufgelistet. Die Schlüssel &#039;&#039;confc&#039;&#039;, &#039;&#039;con&#039;&#039; und &#039;&#039;gcon&#039;&#039; zeigen die Verbrauchsprognose, den Verbrauch und den Netzbezug der jeweiligen Stunde des gewählten Tages.&lt;br /&gt;
Die Stunde &amp;quot;99&amp;quot; zeigt die Summen dieser Schlüsssel für den Tag:&lt;br /&gt;
&lt;br /&gt;
      99 =&amp;gt; etotal: , pvfc: 782, pvrl: 0, rad1h: -&lt;br /&gt;
            confc: 14540, con: 13873, gcon: 13873, gfeedin: 0&lt;br /&gt;
            batintotal: , batin: 0, batouttotal: , batout: 0&lt;br /&gt;
            batmaxsoc: -, batsetsoc: -&lt;br /&gt;
            wid: , wcc: , wrp: , pvcorrf: , dayname: So&lt;br /&gt;
            cyclescsm01: 0&lt;br /&gt;
            cyclescsm02: 0&lt;br /&gt;
            cyclescsm03: 0&lt;br /&gt;
            cyclescsm04: 1, hourscsme04: 0.00&lt;br /&gt;
            cyclescsm05: 0&lt;br /&gt;
            cyclescsm06: 0&lt;br /&gt;
            cyclescsm07: 1, hourscsme07: 0.00&lt;br /&gt;
            cyclescsm08: 1, hourscsme08: 0.00&lt;br /&gt;
            cyclescsm09: 1, hourscsme09: 0.03 &lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wurden für den Tag 14540 Wh Verbrauch prognostiziert, 13873 Wh tatsächlich verbraucht und davon 13873 Wh aus dem Netz bezogen. Leider war an diesem Tag keinerlei PV Ertrag vorhanden, was man auch an dem Schlüssel &#039;&#039;pvrl&#039;&#039; erkennen kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Den Inhalt des pvCircular-Speichers kann mit dem Befehl  &lt;br /&gt;
&lt;br /&gt;
     &amp;quot;get ... pvCircular [Tag]&amp;quot;&lt;br /&gt;
&lt;br /&gt;
angezeigt werden. Das nachfolgende Beispiel zeigt die Ausgabe für die Tagesstunde 23:&lt;br /&gt;
&lt;br /&gt;
 23 =&amp;gt; pvapifc: 0, pvaifc: -, pvfc: 0, aihit: 0, pvrl: 0&lt;br /&gt;
       batin01: 0, batin02: -, batin03: -&lt;br /&gt;
       batout01: 619, batout02: -, batout03: -&lt;br /&gt;
       confc: 650, gcon: 23, gfeedin: 0, wcc: 40, rr1c: 0.00&lt;br /&gt;
       temp: -6.00, wid: 100, wtxt: Bewölkungsentwicklung nicht beobachtet&lt;br /&gt;
       pprl01: -, pprl02: -, pprl03: -&lt;br /&gt;
       ... &lt;br /&gt;
       con_all =&amp;gt; Sa  @ 617 762&lt;br /&gt;
                  Di  @ 693 645&lt;br /&gt;
                  Mo  @ 620 679&lt;br /&gt;
                  So  @ 669 666 636&lt;br /&gt;
                  Mi  @ 701 626&lt;br /&gt;
                  Do  @ 612 642&lt;br /&gt;
                  Fr  @ 615 606&lt;br /&gt;
&lt;br /&gt;
Der Schüssel &#039;&#039;con_all&#039;&#039; enthält einen Hash aus Arrays die für jeden Wochentag (Mo..So) bis zu 30 Verbrauchswerte (in Wh) für die angezeigte Stunde speichern. Wie hier erkennbar ist, wurden an den drei vergangenen Sonntagen jweils 669 Wh, 666 Wh bzw. 636 Wh in der Stunde 23 (22:00-22:59) verbraucht.&lt;br /&gt;
Der Median aus diesen Werten geht in die Verbrauchsprognose ein. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Die Wochentagsnamen Mo..So sind von den installierten Locales auf Betriebsystemebene abhängig. Ist keine deutsche locale installiert, werden die englischen Wochentagsnamen Mon..Sun verwendet.    &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ausblick (ab V 2.0.0, aktuell in Entwicklung):&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Die Verbrauchsprognose kann zukünftig auf &#039;&#039;&#039;herkömmliche Weise (Legacy)&#039;&#039;&#039; erstellt oder &#039;&#039;&#039;durch eine KI&#039;&#039;&#039; erstellt werden. Es ist auch eine prozentual einstellbare Kombination aus beiden Ergebnissen möglich. Weiter unten werden beide Varianten beschrieben. Bitte beachten, dass beide Technologien ihre spezifischen Attribute zur Einstellung haben.&lt;br /&gt;
&lt;br /&gt;
Die KI-gestützte Prognose verwendet Langzeitdaten, die sich in einem speziellen Datenspeicher befinden und mit&lt;br /&gt;
&lt;br /&gt;
 get &amp;lt;Name&amp;gt; valDecTree aiRawData&lt;br /&gt;
&lt;br /&gt;
eingesehen werden können. Wie lange diese Daten aufbewahrt werden, ist mit dem Attribut&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; aiControl-&amp;gt;aiStorageDuration&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
einstellbar. Eine Pflege dieser Daten ist mit dem Befehl&lt;br /&gt;
&lt;br /&gt;
 set &amp;lt;Name&amp;gt; reset aiData ...&lt;br /&gt;
&lt;br /&gt;
möglich.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Wie wird der Verbrauch des Hauses ermittelt und gespeichert? ===&lt;br /&gt;
&lt;br /&gt;
Die Verbrauchsdaten des Hauses werden auf Stundenbasis ermittelt und gespeichert. Das &amp;quot;Haus&amp;quot; steht als Synonym aller im Kontext des Solarforecast Devices zusammengeführten Inverter (setupInverterDevXX), sonstigen Erzeuger (setupOtherProducerXX), Netzanschlüsse (setupMeterDev), Verbraucher (consumerXX) und Batterien (setupBatteryDev).&lt;br /&gt;
&lt;br /&gt;
Alle diese Daten werden durch das Modul mit jedem ausgeführten Zyklus (Attribut plantControl-&amp;gt;cycleInterval) und ebenfalls bei auftreten von Events eines als &#039;asynchron&#039; definierten Devices gesammelt. Daraus wird permanent ein aktualisierter Verbrauch berechnet. Die Berechnung beschreibt folgende Formel: &lt;br /&gt;
&lt;br /&gt;
 PV-Erzeugung + sonstige Erzeugung - Netzeinspeisung + Netzbezug - Batterieladung + Batterieentladung - Verbrauch = 0&lt;br /&gt;
&lt;br /&gt;
bzw.&lt;br /&gt;
 &lt;br /&gt;
 Verbrauch (Wh) = PV-Erzeugung + sonstige Erzeugung - Netzeinspeisung + Netzbezug - Batterieladung + Batterieentladung&lt;br /&gt;
            con = PV           + PP                 - GridIn          + GridCon   - BatIn          + BatOut&lt;br /&gt;
&lt;br /&gt;
Die PV-Erzeugung beinhaltet die Summe aller durch die angegebnen Inverter (setupInverterDev01 .. setupInverterDevXX) erzeugten Energien. Die &amp;quot;sonstige Erzeugung&amp;quot; summiert sich aus den Werten aller angegebenen Producer (setupOtherProducer01 .. setupOtherProducerXX). Der Verbrauch wird durch die registrierten Geräte consumerXX teilweise direkt erfasst, ist aber grundsätzlich unvollständig da nicht alle Verbrauchswerte im &amp;quot;Haus&amp;quot; gemessen und durch das Modul erfasst werden können.&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt das Ergebnis bei 300 Wh PV-Erzeugung und gleichzeitige 500 Wh Netzbezug:&lt;br /&gt;
&lt;br /&gt;
 Verbrauch = 300 + 0 - 0 + 500 - 0 + 0 = 800 Wh&lt;br /&gt;
&lt;br /&gt;
Bei 1300Wh PV-Erzeugung, 100 Wh Netzeinspeisung sowie 200 Wh Batterieladung ergibt sich der Verbrauch zu:&lt;br /&gt;
&lt;br /&gt;
 Verbrauch = 1300 + 0 - 100 + 0 - 200 + 0 = 1000 Wh&lt;br /&gt;
&lt;br /&gt;
Ohne Erzeugung, aber mit der Energielieferung von 500 Wh aus der Batterie, 800 Wh Netzbezug (mit einem Anteil Batterienachladung aus dem Netz von 200 Wh) sieht die Verbrauchsrechnung wie folgt aus: &lt;br /&gt;
&lt;br /&gt;
 Verbrauch = 0 + 0 - 0 + 800 - 200 + 500 = 1100 Wh&lt;br /&gt;
&lt;br /&gt;
Der so ermittelte Verbrauchsert wird mit jedem Zyklus in der pvHistory im Schlüssel &amp;quot;con&amp;quot; gespeichert. Man kann sich die gespeicherten Werte mit dem Befehl&lt;br /&gt;
&lt;br /&gt;
 get &amp;lt;name&amp;gt; pvHistory [&amp;lt;Tag&amp;gt;]&lt;br /&gt;
&lt;br /&gt;
angezeigt werden. Nachfolgendes Beispiel zeigt einen Datensatz für die Stunde 8 eines Tages:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      08 =&amp;gt; pvfc: 0, pvrl: 0, pvrlvd: 1, rad1h: -&lt;br /&gt;
            etotali01: 62940734, etotali02: 2928860, etotali03: -&lt;br /&gt;
            pvrl01: 0, pvrl02: 0, pvrl03: -&lt;br /&gt;
            etotalp01: -, etotalp02: -, etotalp03: -&lt;br /&gt;
            pprl01: -, pprl02: -, pprl03: -&lt;br /&gt;
            confc: 630, con: 962, gcons: 962, conprice: 0.2958&lt;br /&gt;
            gfeedin: 0, feedprice: 0.1269&lt;br /&gt;
            DoN: 0, sunaz: 120, sunalt: -3&lt;br /&gt;
            batintotal: 3713815.07742543, batouttotal: 3604468.26993988, batin: 0, batout: 0&lt;br /&gt;
            wid: 161, wcc: 89, rr1c: 0.00, pvcorrf: 0.27/0.00 temp: 7.40, &lt;br /&gt;
            csmt01: 110996.12, csme01: 32.1399999999994, minutescsm01: 30&lt;br /&gt;
            minutescsm02: 0&lt;br /&gt;
            csmt03: 2513.67, csme03: 0, minutescsm03: 0&lt;br /&gt;
            csmt04: 1581293.6, csme04: 136.5, minutescsm04: 60&lt;br /&gt;
            csmt05: 1662.17, csme05: 0, minutescsm05: 0&lt;br /&gt;
            csmt06: 90.53, csme06: 0, minutescsm06: 0&lt;br /&gt;
            csmt07: 39.75, csme07: 0, minutescsm07: 0&lt;br /&gt;
            csmt08: 38050, csme08: 0, minutescsm08: 0&lt;br /&gt;
            csmt09: 131627, csme09: 33.2000000000116, minutescsm09: 39&lt;br /&gt;
            minutescsm10: 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Schlüssel &amp;quot;con&amp;quot; ist der gespeicherte Verbrauch von 962 Wh ersichtlich.&lt;br /&gt;
&lt;br /&gt;
Zur Laufzeit bekommt man mit dem Attribut &#039;&#039;ctrlDebug=collectData&#039;&#039; einen Einblick in die Verbrauchsermittlung bei jedem Zyklus und kann so die Eingangswerte und das daraus resultierende Ergebnis im FHEM Log nachverfolgen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
2024.11.28 11:38:20.080 1: SolCast DEBUG&amp;gt; EnergyConsumption input -&amp;gt; PV: 96, PP: 0, GridIn: 0, GridCon: 582, BatIn: 5, BatOut: 0&lt;br /&gt;
2024.11.28 11:38:20.081 1: SolCast DEBUG&amp;gt; EnergyConsumption result -&amp;gt; 673 Wh&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Die Legacy-Verbrauchsprognose einstellen ===&lt;br /&gt;
==== Wie wird die Legacy-Verbrauchsprognose erstellt? ====&lt;br /&gt;
&lt;br /&gt;
Aus den gespeicherten con-Werten (Verbrauchsdaten) der pvCircular (Schlüssel con_all) sowie Einträgen der pvHistory wird der Median der historischen Tage ermittelt und für den kommenden Tag bzw. die kommen Stunden zur Prognose angewendet. Dabei geht per default jeder verfügbare historische Tag gleichberechtigt in die Prognose ein. Mit dem Attribut &#039;&#039;&#039;plantControl-&amp;gt;consForecastIdentWeekdays=1&#039;&#039;&#039; kann festgelegt werden, dass nur gleiche Wochentage (Mo..So) für die Prognose verwendet werden. Hierbei spielt die Vermutung, dass das Verbrauchsverhalten eine gewisse Korrelation zum Wochentag hat, eine Rolle. &lt;br /&gt;
&lt;br /&gt;
Verwendet man die Einstellung consForecastIdentWeekdays=1, hat es sich als vorteilhaft erwiesen, das Attribut &#039;&#039;&#039;plantControl-&amp;gt;consForecastLastDays&#039;&#039;&#039; auf einen niedrigeren Wert als den Default zu setzen. Eine Einstellung auf &#039;8&#039; zum Beispiel verwendet den Median der gleichen Wochentage der vergangenenen 8 Wochen. Dadurch wird nicht zu weit in die Vergangenheit verzweigt und so eine langsame Veränderung des Verbrauchsmedian, zum Beispiel hervorgerufen durch den Übergang vom Winter in das Frühjahr hinein, abgebildet.&lt;br /&gt;
&lt;br /&gt;
Weiteren Einfluß auf die Verbrauchsprognose kann mit dem Schlüssel &#039;&#039;&#039;exconfc&#039;&#039;&#039; im Consumerattribut genommen werden. Insbesondere bei der unregelmäßigen Nutzung von Verbrauchern mit hoher Leistung kann die Projektion der aufgezeichneten historischen Werte in die Prognose zu unverhältnismäßig hohen Verbrauchswerwartunden führen. &lt;br /&gt;
&lt;br /&gt;
Möglicherweise führt in Fällen die Verwendung eine der nachfolgenden Optionen zu einem besseren Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;1 -&#039;&#039;&#039; die allgemeine Verbrauchsprognose wird um die gespeicherten Energieverbrauchsanteile reduziert.&lt;br /&gt;
* &#039;&#039;&#039;2 -&#039;&#039;&#039; wie bei &#039;1&#039;, jedoch gehen die Planungsdaten des Verbrauchers bei der Prognose der kommenden Stunden wieder mit ein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird &#039;&#039;&#039;exconfc&#039;&#039;&#039; in einem der Consumer verwendet, sollte&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;plantControl-&amp;gt;consForecastIdentWeekdays=1&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;plantControl-&amp;gt;consForecastLastDays=4&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
eingestellt werden. Hintergrund ist, dass die Verbrauchsanteile der jeweiligen Verbraucher nur maximal 31 Tage in der pvHistory verfügbar sind. Für längere Zeiträume stehen nur Gesamtsummen des Verbrauchs in der pvCircular zu Verfügung.  &lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;&#039;exconfc=1&#039;&#039;&#039; werden die in der Historie aufgezeichneten Verbrauchsbestandteile aus einer Prognose herausgerechnet. Konkret werden die in der pvHistory aufgezeichneten Verbrauchsbestandteile für die relevante Stunde ermittelt und daraus ein Durchschnitt gebildet der vom Prognosewert subtrahiert wird. Mit dem Attributwert plantControl-&amp;gt;consForecastIdentWeekdays=1 werden wiederum nur identische Wochentage (Mo .. So) zusammengefasst.&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;&#039;exconfc=2&#039;&#039;&#039; erfolgt ebenso die Eliminierung des Verbrauchsanteils, es wird jedoch auf die Planungsdaten für diesen Verbraucher zugegriffen und die geplanten Energieanteile wiederum der Verbrauchsprognose für die kommenden Stunden hinzugerechnet.&lt;br /&gt;
&lt;br /&gt;
In beiden Anwendungsfällen ist es notwendig, dass dem Modul durch die Angabe entsprechender Readings der Energieverbrauch im Setup des Consumers bekannt gemacht wird damit diese Energieanteile registriert werden können. Allgemein funktioniert die Verbrauchsprognose gut wenn Verbrauchsprozesse regelmäßig in einem wiederkehrenden Zeitraster ablaufen, der Verbrauch durch persönliche Rituale bestimmt ist. So zum Beispiel könnte am Dienstag und Samstag gewöhnlich die Waschmaschine laufen, das E-Auto täglich aufgeladen werden und gebügelt wird oft am Sonntag Nachmittag.&lt;br /&gt;
&lt;br /&gt;
Unregelmäßige Nutzung, vor allem vom Großverbrauchern, lässt sich nur sehr schwer und ungenügend auf zukünftige Verbrauchsprognosen projizieren.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis der Prognose wird im Kopf der Grafik in der Zeile &#039;&#039;Verbrauch&#039;&#039; sowie in diversen Readings wie &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RestOfDayConsumptionForecast&#039;&#039;&#039; (Verbrauchsprognose für den Rest des Tages)&lt;br /&gt;
* &#039;&#039;&#039;NextHours_Sum04_ConsumptionForecast&#039;&#039;&#039; (Verbrauchsprognose für die nächsten 4 Stunden)&lt;br /&gt;
* &#039;&#039;&#039;Tomorrow_ConsumptionForecast&#039;&#039;&#039; (Verbrauchsprognose für den kommenden Tag)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
angezeigt.&lt;br /&gt;
&lt;br /&gt;
Weitere Aggregationen kann man sich über das Attribut &#039;&#039;&#039;ctrlStatisticReadings&#039;&#039;&#039; bei Bedarf zuschalten:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;conForecastTillNextSunrise&#039;&#039;&#039; - Verbrauchsprognose von aktueller Stunde bis zum kommenden Sonnenaufgang&lt;br /&gt;
* &#039;&#039;&#039;todayConForecastTillSunset&#039;&#039;&#039; - Verbrauchsprognose von aktueller Stunde bis Stunde vor Sonnenuntergang&lt;br /&gt;
* &#039;&#039;&#039;todayConsumptionForecast&#039;&#039;&#039; - Verbrauchsprognose aufgesplittet pro Stunde des aktuellen Tages (01-24) &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Debugging der Legacy-Verbrauchsprognose ====&lt;br /&gt;
&lt;br /&gt;
Um sich einen Einblick über die Erstellung der Verbrauchsprognose zu verschaffen, bietet sich die Einschaltung von:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; ctrlDebug consumption_long&lt;br /&gt;
&lt;br /&gt;
an. Mit diesem gesetzten Attribut wird die Erstellung der Prognose im Log protokolliert:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
2025.02.27 19:52:00.063 1: SolCast DEBUG&amp;gt; ################### Start Consumption forecast ###################&lt;br /&gt;
2025.02.27 19:52:00.063 1: SolCast DEBUG&amp;gt; Basics - installed locale: de_DE.UTF-8, used scheme: DE&lt;br /&gt;
2025.02.27 19:52:00.064 1: SolCast DEBUG&amp;gt; process Today dayname: Do, Tomorrow dayname: Fr&lt;br /&gt;
2025.02.27 19:52:00.065 1: SolCast DEBUG&amp;gt; consumer &#039;03&#039; register for exclude day 13, hod: 01 - 74.43 Wh&lt;br /&gt;
2025.02.27 19:52:00.065 1: SolCast DEBUG&amp;gt; consumer &#039;03&#039; register for exclude day 13, hod: 10 - 290.77 Wh&lt;br /&gt;
2025.02.27 19:52:00.065 1: SolCast DEBUG&amp;gt; consumer &#039;03&#039; register for exclude day 13, hod: 24 - 660.70 Wh&lt;br /&gt;
2025.02.27 19:52:00.066 1: SolCast DEBUG&amp;gt; consumer &#039;03&#039; register for exclude day 20, hod: 07 - 459.93 Wh&lt;br /&gt;
2025.02.27 19:52:00.066 1: SolCast DEBUG&amp;gt; consumer &#039;07&#039; register for exclude day 20, hod: 02 - 0.33 Wh&lt;br /&gt;
2025.02.27 19:52:00.067 1: SolCast DEBUG&amp;gt; consumer &#039;03&#039; register for exclude day 30, hod: 08 - 264.78 Wh&lt;br /&gt;
2025.02.27 19:52:00.067 1: SolCast DEBUG&amp;gt; ################### Consumption forecast for the next Hours (new median) ###################&lt;br /&gt;
2025.02.27 19:52:00.067 1: SolCast DEBUG&amp;gt; excl. hist 74 Wh for Hour 01, Considered value numbers: 1&lt;br /&gt;
2025.02.27 19:52:00.067 1: SolCast DEBUG&amp;gt; estimated cons of Hour 01: 436 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.068 1: SolCast DEBUG&amp;gt; excl. hist 0 Wh for Hour 02, Considered value numbers: 1&lt;br /&gt;
2025.02.27 19:52:00.068 1: SolCast DEBUG&amp;gt; estimated cons of Hour 02: 428 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.068 1: SolCast DEBUG&amp;gt; estimated cons of Hour 03: 458 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.068 1: SolCast DEBUG&amp;gt; estimated cons of Hour 04: 503 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.069 1: SolCast DEBUG&amp;gt; estimated cons of Hour 05: 489 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.069 1: SolCast DEBUG&amp;gt; estimated cons of Hour 06: 482 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.069 1: SolCast DEBUG&amp;gt; excl. hist 460 Wh for Hour 07, Considered value numbers: 1&lt;br /&gt;
2025.02.27 19:52:00.069 1: SolCast DEBUG&amp;gt; estimated cons of Hour 07: 274 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.070 1: SolCast DEBUG&amp;gt; excl. hist 265 Wh for Hour 08, Considered value numbers: 1&lt;br /&gt;
2025.02.27 19:52:00.070 1: SolCast DEBUG&amp;gt; estimated cons of Hour 08: 441 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.070 1: SolCast DEBUG&amp;gt; estimated cons of Hour 09: 558 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.070 1: SolCast DEBUG&amp;gt; excl. hist 291 Wh for Hour 10, Considered value numbers: 1&lt;br /&gt;
2025.02.27 19:52:00.071 1: SolCast DEBUG&amp;gt; estimated cons of Hour 10: 443 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.071 1: SolCast DEBUG&amp;gt; estimated cons of Hour 11: 881 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.071 1: SolCast DEBUG&amp;gt; estimated cons of Hour 12: 794 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.072 1: SolCast DEBUG&amp;gt; estimated cons of Hour 13: 840 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.072 1: SolCast DEBUG&amp;gt; estimated cons of Hour 14: 660 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.072 1: SolCast DEBUG&amp;gt; estimated cons of Hour 15: 812 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.072 1: SolCast DEBUG&amp;gt; estimated cons of Hour 16: 752 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.073 1: SolCast DEBUG&amp;gt; estimated cons of Hour 17: 597 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.073 1: SolCast DEBUG&amp;gt; estimated cons of Hour 18: 652 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.073 1: SolCast DEBUG&amp;gt; estimated cons of Hour 19: 634 Wh, Considered value numbers: 4&lt;br /&gt;
2025.02.27 19:52:00.073 1: SolCast DEBUG&amp;gt; estimated cons of Hour 20: 628 Wh, Considered value numbers: 3&lt;br /&gt;
2025.02.27 19:52:00.074 1: SolCast DEBUG&amp;gt; estimated cons of Hour 21: 713 Wh, Considered value numbers: 3&lt;br /&gt;
2025.02.27 19:52:00.074 1: SolCast DEBUG&amp;gt; estimated cons of Hour 22: 596 Wh, Considered value numbers: 3&lt;br /&gt;
2025.02.27 19:52:00.074 1: SolCast DEBUG&amp;gt; estimated cons of Hour 23: 629 Wh, Considered value numbers: 3&lt;br /&gt;
2025.02.27 19:52:00.074 1: SolCast DEBUG&amp;gt; excl. hist 661 Wh for Hour 24, Considered value numbers: 1&lt;br /&gt;
2025.02.27 19:52:00.075 1: SolCast DEBUG&amp;gt; estimated cons of Hour 24: 660 Wh, Considered value numbers: 3&lt;br /&gt;
2025.02.27 19:52:00.075 1: SolCast DEBUG&amp;gt; ################### Consumption forecast for the next day (new median) ###################&lt;br /&gt;
2025.02.27 19:52:00.075 1: SolCast DEBUG&amp;gt; estimated cons Tomorrow: 16848 Wh, Individual hourly values considered: 72, exclude: 0 Wh (avg of 0 entities)&lt;br /&gt;
2025.02.27 19:52:00.075 1: SolCast DEBUG&amp;gt; ################### Store Consumption forecast values (new median) ###################&lt;br /&gt;
2025.02.27 19:52:00.076 1: SolCast DEBUG&amp;gt; store &#039;NextHour00&#039; hod &#039;20&#039; confc: 628, confcEx: 628&lt;br /&gt;
2025.02.27 19:52:00.076 1: SolCast DEBUG&amp;gt; store circular/history hod &#039;20&#039; confc: 628&lt;br /&gt;
2025.02.27 19:52:00.076 1: SolCast DEBUG&amp;gt; store &#039;NextHour01&#039; hod &#039;21&#039; confc: 713, confcEx: 713&lt;br /&gt;
2025.02.27 19:52:00.077 1: SolCast DEBUG&amp;gt; store circular/history hod &#039;21&#039; confc: 713&lt;br /&gt;
2025.02.27 19:52:00.077 1: SolCast DEBUG&amp;gt; store &#039;NextHour02&#039; hod &#039;22&#039; confc: 596, confcEx: 596&lt;br /&gt;
2025.02.27 19:52:00.077 1: SolCast DEBUG&amp;gt; store circular/history hod &#039;22&#039; confc: 596&lt;br /&gt;
2025.02.27 19:52:00.077 1: SolCast DEBUG&amp;gt; store &#039;NextHour03&#039; hod &#039;23&#039; confc: 629, confcEx: 629&lt;br /&gt;
2025.02.27 19:52:00.078 1: SolCast DEBUG&amp;gt; store circular/history hod &#039;23&#039; confc: 629&lt;br /&gt;
2025.02.27 19:52:00.078 1: SolCast DEBUG&amp;gt; store &#039;NextHour04&#039; hod &#039;24&#039; confc: 660, confcEx: 660&lt;br /&gt;
2025.02.27 19:52:00.078 1: SolCast DEBUG&amp;gt; store circular/history hod &#039;24&#039; confc: 660&lt;br /&gt;
2025.02.27 19:52:00.079 1: SolCast DEBUG&amp;gt; store &#039;NextHour05&#039; hod &#039;01&#039; confc: 436, confcEx: 436&lt;br /&gt;
2025.02.27 19:52:00.079 1: SolCast DEBUG&amp;gt; store &#039;NextHour06&#039; hod &#039;02&#039; confc: 428, confcEx: 428&lt;br /&gt;
2025.02.27 19:52:00.079 1: SolCast DEBUG&amp;gt; store &#039;NextHour07&#039; hod &#039;03&#039; confc: 458, confcEx: 458&lt;br /&gt;
2025.02.27 19:52:00.079 1: SolCast DEBUG&amp;gt; store &#039;NextHour08&#039; hod &#039;04&#039; confc: 503, confcEx: 503&lt;br /&gt;
2025.02.27 19:52:00.080 1: SolCast DEBUG&amp;gt; store &#039;NextHour09&#039; hod &#039;05&#039; confc: 489, confcEx: 489&lt;br /&gt;
2025.02.27 19:52:00.080 1: SolCast DEBUG&amp;gt; store &#039;NextHour10&#039; hod &#039;06&#039; confc: 482, confcEx: 482&lt;br /&gt;
2025.02.27 19:52:00.080 1: SolCast DEBUG&amp;gt; store &#039;NextHour11&#039; hod &#039;07&#039; confc: 274, confcEx: 274&lt;br /&gt;
2025.02.27 19:52:00.081 1: SolCast DEBUG&amp;gt; store &#039;NextHour12&#039; hod &#039;08&#039; confc: 441, confcEx: 441&lt;br /&gt;
2025.02.27 19:52:00.081 1: SolCast DEBUG&amp;gt; store &#039;NextHour13&#039; hod &#039;09&#039; confc: 558, confcEx: 558&lt;br /&gt;
2025.02.27 19:52:00.081 1: SolCast DEBUG&amp;gt; store &#039;NextHour14&#039; hod &#039;10&#039; confc: 443, confcEx: 443&lt;br /&gt;
2025.02.27 19:52:00.081 1: SolCast DEBUG&amp;gt; store &#039;NextHour15&#039; hod &#039;11&#039; confc: 881, confcEx: 881&lt;br /&gt;
2025.02.27 19:52:00.082 1: SolCast DEBUG&amp;gt; store &#039;NextHour16&#039; hod &#039;12&#039; confc: 794, confcEx: 794&lt;br /&gt;
2025.02.27 19:52:00.082 1: SolCast DEBUG&amp;gt; store &#039;NextHour17&#039; hod &#039;13&#039; confc: 840, confcEx: 840&lt;br /&gt;
2025.02.27 19:52:00.082 1: SolCast DEBUG&amp;gt; store &#039;NextHour18&#039; hod &#039;14&#039; confc: 660, confcEx: 660&lt;br /&gt;
2025.02.27 19:52:00.083 1: SolCast DEBUG&amp;gt; store &#039;NextHour19&#039; hod &#039;15&#039; confc: 812, confcEx: 812&lt;br /&gt;
2025.02.27 19:52:00.083 1: SolCast DEBUG&amp;gt; store &#039;NextHour20&#039; hod &#039;16&#039; confc: 752, confcEx: 752&lt;br /&gt;
2025.02.27 19:52:00.083 1: SolCast DEBUG&amp;gt; store &#039;NextHour21&#039; hod &#039;17&#039; confc: 597, confcEx: 597&lt;br /&gt;
2025.02.27 19:52:00.083 1: SolCast DEBUG&amp;gt; store &#039;NextHour22&#039; hod &#039;18&#039; confc: 652, confcEx: 652&lt;br /&gt;
2025.02.27 19:52:00.084 1: SolCast DEBUG&amp;gt; store &#039;NextHour23&#039; hod &#039;19&#039; confc: 634, confcEx: 634&lt;br /&gt;
2025.02.27 19:52:00.084 1: SolCast DEBUG&amp;gt; store &#039;NextHour24&#039; hod &#039;20&#039; confc: 628, confcEx: 628&lt;br /&gt;
2025.02.27 19:52:00.084 1: SolCast DEBUG&amp;gt; store &#039;NextHour25&#039; hod &#039;21&#039; confc: 713, confcEx: 713&lt;br /&gt;
2025.02.27 19:52:00.084 1: SolCast DEBUG&amp;gt; store &#039;NextHour26&#039; hod &#039;22&#039; confc: 596, confcEx: 596&lt;br /&gt;
2025.02.27 19:52:00.085 1: SolCast DEBUG&amp;gt; store &#039;NextHour27&#039; hod &#039;23&#039; confc: 629, confcEx: 629&lt;br /&gt;
2025.02.27 19:52:00.085 1: SolCast DEBUG&amp;gt; store &#039;NextHour28&#039; hod &#039;24&#039; confc: 660, confcEx: 660&lt;br /&gt;
2025.02.27 19:52:00.086 1: SolCast DEBUG&amp;gt; consumption calculated - day: 27, hod: 20, con: 574 Wh&lt;br /&gt;
2025.02.27 19:52:00.086 1: SolCast DEBUG&amp;gt; write pvCircular consumption - hod: 99, todayConsumption: 11210 Wh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Ausgabe startet mit &#039;&#039;&amp;quot;Start Consumption forecast&#039;&#039;&amp;quot;, es werden die zu exkludierenden historischen Daten für jeden Consumer bzgl. jedem Tag (day) und Stunde des Tages (hod) getrennt registriert. Diese Werte werden durch die gespeicherte Einträge in der pvHistory (max. 31 historische Tage) geliefert. &lt;br /&gt;
&lt;br /&gt;
Im nächsten Abschnitt &#039;&#039;&amp;quot;Consumption forecast for the next Hours (new median)&amp;quot;&#039;&#039; werden die Prognosen für die nächsten Stunden kalkuliert und die zuvor registrierten Excludes angewendet. Die Prognose für den kommenden Tag ist im Abschnitt &#039;&#039;&amp;quot;Consumption forecast for the next day (new median)&amp;quot;&#039;&#039; protokolliert. Die Prognose für den kommenden Tag ist nicht einfach die Summe der Prognose der nächsten Stunden, denn in den kommenden Stunden werden auch die verfügbaren Planungen der Consumer einbezogen. Für den kommenden Tag können diese Werte unter Umständen nicht einbezogen werden da sie zum Zeitpunkt X noch nicht verfügbar sind.&lt;br /&gt;
&lt;br /&gt;
Im Abschnitt &#039;&#039;&amp;quot;Store Consumption forecast values (new median)&amp;quot;&#039;&#039; erscheinen die effektiv gespeicherten Werte. Diese sind die Grandlage für die grafische Darstellung sowie weiteren Kalkulationen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Wie kann eine fehlerhafte Legacy-Verbrauchsprognose korrigiert werden? ====&lt;br /&gt;
Wie im vorherigen Abschnitt beschrieben, wird die Prognose aus den gespeicherten &amp;quot;con&amp;quot;-Werten der vergangenen Tage (bzw. Stunden) abgeleitet. &lt;br /&gt;
Grundsätzlich muß zunächst sichergestellt werden, dass die auszulesenden Readings der angegebenen Energiezähler sowie deren Einheiten! korrekt eingestellt sind. Das gilt ebenfalls für die registrierten Verbraucher im Modul.&lt;br /&gt;
&lt;br /&gt;
Für einen ersten Überblick bietet sich das Debug Attribut an zu setzen:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; ctrlDebug consumption_long&lt;br /&gt;
&lt;br /&gt;
Beispielausgabe des Debug:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
2024.09.21 13:28:27.041 1: SolCast DEBUG&amp;gt; ################### Consumption forecast for the next day ###################&lt;br /&gt;
2024.09.21 13:28:27.042 1: SolCast DEBUG&amp;gt; History Consumption day &amp;gt;01&amp;lt; considering possible exclusions: 14082&lt;br /&gt;
2024.09.21 13:28:27.042 1: SolCast DEBUG&amp;gt; History Consumption day &amp;gt;08&amp;lt; considering possible exclusions: 16446&lt;br /&gt;
2024.09.21 13:28:27.042 1: SolCast DEBUG&amp;gt; History Consumption day &amp;gt;15&amp;lt; considering possible exclusions: 14568&lt;br /&gt;
2024.09.21 13:28:27.043 1: SolCast DEBUG&amp;gt; History Consumption day &amp;gt;25&amp;lt; considering possible exclusions: 15522&lt;br /&gt;
2024.09.21 13:28:27.043 1: SolCast DEBUG&amp;gt; estimated Consumption for tomorrow: 15154, days for avg: 4&lt;br /&gt;
2024.09.21 13:28:27.043 1: SolCast DEBUG&amp;gt; ################### Consumption forecast for the next hours ###################&lt;br /&gt;
2024.09.21 13:28:27.044 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 07, hod: 14 -&amp;gt; 850 Wh&lt;br /&gt;
2024.09.21 13:28:27.044 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 14, hod: 14 -&amp;gt; 643 Wh&lt;br /&gt;
2024.09.21 13:28:27.044 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 24, hod: 14 -&amp;gt; 590 Wh&lt;br /&gt;
2024.09.21 13:28:27.045 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 31, hod: 14 -&amp;gt; 522 Wh&lt;br /&gt;
2024.09.21 13:28:27.045 1: SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 13:00:00, confc: 651, days for avg: 4, hist. consumption registered consumers: 560.97&lt;br /&gt;
2024.09.21 13:28:27.046 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 07, hod: 15 -&amp;gt; 720 Wh&lt;br /&gt;
2024.09.21 13:28:27.046 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 14, hod: 15 -&amp;gt; 743 Wh&lt;br /&gt;
2024.09.21 13:28:27.046 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 24, hod: 15 -&amp;gt; 897 Wh&lt;br /&gt;
2024.09.21 13:28:27.047 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 31, hod: 15 -&amp;gt; 557 Wh&lt;br /&gt;
2024.09.21 13:28:27.047 1: SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 14:00:00, confc: 729, days for avg: 4, hist. consumption registered consumers: 620.97&lt;br /&gt;
2024.09.21 13:28:27.047 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 07, hod: 16 -&amp;gt; 676 Wh&lt;br /&gt;
2024.09.21 13:28:27.048 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 14, hod: 16 -&amp;gt; 790 Wh&lt;br /&gt;
2024.09.21 13:28:27.048 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 24, hod: 16 -&amp;gt; 785 Wh&lt;br /&gt;
2024.09.21 13:28:27.048 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 31, hod: 16 -&amp;gt; 581 Wh&lt;br /&gt;
2024.09.21 13:28:27.049 1: SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 15:00:00, confc: 708, days for avg: 4, hist. consumption registered consumers: 647.29&lt;br /&gt;
2024.09.21 13:28:27.049 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 07, hod: 17 -&amp;gt; 622 Wh&lt;br /&gt;
2024.09.21 13:28:27.050 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 14, hod: 17 -&amp;gt; 639 Wh&lt;br /&gt;
2024.09.21 13:28:27.050 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 24, hod: 17 -&amp;gt; 646 Wh&lt;br /&gt;
2024.09.21 13:28:27.050 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 31, hod: 17 -&amp;gt; 572 Wh&lt;br /&gt;
2024.09.21 13:28:27.051 1: SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 16:00:00, confc: 619, days for avg: 4, hist. consumption registered consumers: 618.30&lt;br /&gt;
2024.09.21 13:28:27.051 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 07, hod: 18 -&amp;gt; 596 Wh&lt;br /&gt;
2024.09.21 13:28:27.051 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 14, hod: 18 -&amp;gt; 614 Wh&lt;br /&gt;
2024.09.21 13:28:27.052 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 24, hod: 18 -&amp;gt; 580 Wh&lt;br /&gt;
2024.09.21 13:28:27.052 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 31, hod: 18 -&amp;gt; 480 Wh&lt;br /&gt;
2024.09.21 13:28:27.052 1: SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 17:00:00, confc: 567, days for avg: 4, hist. consumption registered consumers: 583.41&lt;br /&gt;
2024.09.21 13:28:27.053 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 07, hod: 19 -&amp;gt; 615 Wh&lt;br /&gt;
2024.09.21 13:28:27.053 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 14, hod: 19 -&amp;gt; 1659 Wh&lt;br /&gt;
2024.09.21 13:28:27.053 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 24, hod: 19 -&amp;gt; 597 Wh&lt;br /&gt;
2024.09.21 13:28:27.054 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 31, hod: 19 -&amp;gt; 618 Wh&lt;br /&gt;
2024.09.21 13:28:27.054 1: SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 18:00:00, confc: 872, days for avg: 4, hist. consumption registered consumers: 636.97&lt;br /&gt;
2024.09.21 13:28:27.055 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 07, hod: 20 -&amp;gt; 611 Wh&lt;br /&gt;
2024.09.21 13:28:27.055 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 14, hod: 20 -&amp;gt; 1124 Wh&lt;br /&gt;
2024.09.21 13:28:27.055 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 24, hod: 20 -&amp;gt; 546 Wh&lt;br /&gt;
2024.09.21 13:28:27.056 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 31, hod: 20 -&amp;gt; 479 Wh&lt;br /&gt;
2024.09.21 13:28:27.056 1: SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 19:00:00, confc: 690, days for avg: 4, hist. consumption registered consumers: 578.87&lt;br /&gt;
2024.09.21 13:28:27.056 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 07, hod: 21 -&amp;gt; 1474 Wh&lt;br /&gt;
2024.09.21 13:28:27.057 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 14, hod: 21 -&amp;gt; 596 Wh&lt;br /&gt;
2024.09.21 13:28:27.057 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 24, hod: 21 -&amp;gt; 619 Wh&lt;br /&gt;
2024.09.21 13:28:27.057 1: SolCast DEBUG&amp;gt;     historical Consumption added for Sa -&amp;gt; date: 31, hod: 21 -&amp;gt; 433 Wh&lt;br /&gt;
2024.09.21 13:28:27.058 1: SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 20:00:00, confc: 780, days for avg: 4, hist. consumption registered consumers: 584.96&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Im ersten Teil wird die erwartete Consumption für den nächsten Tag unter Berücksichtigung möglicher Ausschlüsse von Verbrauchern ausgegeben. Ausschlüsse von Verbrauchern ergeben sich wenn in dem Verbraucherattribut der Schlüssel &#039;&#039;&#039;exconfc&#039;&#039;&#039; gesetzt ist. Er besagt, dass die Verbrauchswerte des Verbrauchers in eine zukünftige Prognose nicht eingehen sollen. Zum Beispiel wenn ein Verbraucher mit sehr hohen Verbrauchswerten nur sporadisch eingesetzt wird und dadurch die Prognose stark verfälschen würde. Es ist auch zu sehen, dass bedingt durch das Attribut &#039;&#039;&#039;affectConsForecastIdentWeekdays = 1&#039;&#039;&#039; nur die historischen Tage 01, 08, 15 und 25 berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Im zweiten Teil wird die berechnete Erwartung für die nächsten Stunden ausgegeben. &lt;br /&gt;
Zur Beschreibung der Fehlersuche gehen wir davon aus, dass die Prognose von 780 Wh am 2024-09-21 20:00:00 zu hoch erscheint weil am Tag &amp;quot;07&amp;quot; ein Wert von 1474 Wh gespeichert ist:&lt;br /&gt;
&lt;br /&gt;
 SolCast DEBUG&amp;gt; estimated Consumption for Sa -&amp;gt; starttime: 2024-09-21 20:00:00, confc: 780, days for avg: 4, hist. consumption registered consumers: 584.96&lt;br /&gt;
&lt;br /&gt;
Im nächsten Schritt geben wir die historischen Werte für den Tag 07 aus:&lt;br /&gt;
&lt;br /&gt;
 get &amp;lt;Name&amp;gt; pvHistory 07&lt;br /&gt;
&lt;br /&gt;
In dem Datensatz interessiert die Stunde 21. Sie resultiert aus der obigen Angabe &amp;quot;starttime: xxxx-xx-xx 20:00:00&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      21 =&amp;gt; etotal: 64354660, pvfc: 0, pvrl: 0, pvrlvd: 1, rad1h: -&lt;br /&gt;
            etotalp01: -, etotalp02: -, etotalp03: -&lt;br /&gt;
            pprl01: -, pprl02: -, pprl03: -&lt;br /&gt;
            confc: 496, con: 1474, gcons: 23, conprice: 0.2958&lt;br /&gt;
            gfeedin: 5, feedprice: 0.1269&lt;br /&gt;
            DoN: 0, sunaz: 289, sunalt: -8&lt;br /&gt;
            batintotal: 3064096.92456668, batouttotal: 2958021.37946804, batin: 0, batout: 1460&lt;br /&gt;
            wid: 101, wcc: 20, rr1c: 0.00, pvcorrf: 1.00/-temp: 26.00, &lt;br /&gt;
            csmt01: 64262.43, csme01: 28.8099999999977, minutescsm01: 25&lt;br /&gt;
            minutescsm02: 0&lt;br /&gt;
            csmt03: 0, csme03: 0, minutescsm03: 0&lt;br /&gt;
            csmt04: 1389417.4, csme04: 94.5, minutescsm04: 60&lt;br /&gt;
            csmt05: 0, csme05: 0, minutescsm05: 0&lt;br /&gt;
            csmt06: 290.15, csme06: 6.66999999999996, minutescsm06: 54&lt;br /&gt;
            csmt07: 0, csme07: 0, minutescsm07: 0&lt;br /&gt;
            csmt08: 32800, csme08: 0, minutescsm08: 0&lt;br /&gt;
            csmt09: 103987.8, csme09: 38, minutescsm09: 43&lt;br /&gt;
            csmt10: 9151.24999999783, csme10: 3.99999999997999, minutescsm10: 60&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Datensatz sind die Energieverbrauchsanteile der im Device registrierten Verbraucher mit dem Schlüssel &amp;quot;csmeXX&amp;quot; gespeichert. Dabei ist &amp;quot;XX&amp;quot; die Verbrauchernummer. In dem Beispiel existieren die Anteile csme01 und csme03 - csme10. Keiner dieser Verbraucher hat einen auffälligen Verbrauchswert gespeichert, d.h. die Messung der Verbraucher scheidet als Problemquelle aus. Wäre ein unverhältmismäßig hoher Verbrauch bei einem der Verbraucher feststellbar, müssten die Schlüssel &#039;&#039;&#039;pcurr&#039;&#039;&#039; und &#039;&#039;&#039;etotal&#039;&#039;&#039; im consumerXX-Attribut geprüft, sowie die Datenlieferung des Consumerdevices selbst geprüft werden.  &lt;br /&gt;
&lt;br /&gt;
Es wurde offensichtlich ein hoher Verbrauch von einem nicht registrierten Verbraucher verursacht oder durch die Übertragung eines Meßfehlers des Devices, angegeben im Attribut &#039;&#039;&#039;setupMeterDev&#039;&#039;&#039;, in das SolarForecast Device übertragen. Eine weitere Analyse ist an dieser Stelle nicht möglich.&lt;br /&gt;
&lt;br /&gt;
Zur Behebung des falschen Wertes kann ein Reset der gespeicherten Consumption der relevanten Stunde durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
 set &amp;lt;Name&amp;gt; reset consumptionShort 07 21&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Die KI‑Verbrauchsprognose mit AI::FANN aktivieren und einstellen ===&lt;br /&gt;
&lt;br /&gt;
FANN steht für &#039;&#039;&#039;Fast Artificial Neural Network&#039;&#039;&#039;.&lt;br /&gt;
Es handelt sich um eine sehr schnelle, leichtgewichtige Open‑Source‑Bibliothek zur Erstellung und zum Training künstlicher neuronaler Netze. Ein Manual dieser Library ist [https://fann.sourceforge.net/reference/index.html hier] verfügbar.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* FANN ist die &#039;&#039;&#039;technische Grundlage&#039;&#039;&#039; der KI‑Verbrauchsprognose.&lt;br /&gt;
* ws berechnet aus historischen Verbrauchsdaten ein Modell, das zukünftige Werte vorhersagen kann.&lt;br /&gt;
* es ist &#039;&#039;&#039;robust, schnell und ressourcenschonend&#039;&#039;&#039;, ideal für Systeme, die regelmäßig neu trainiert werden müssen.&lt;br /&gt;
* FANN arbeitet mit klassischen Feed‑Forward‑Netzen und Backpropagation‑Training – also bewährten, stabilen Methoden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;AI::FANN&#039;&#039;&#039; ist ein Perl‑Modul, das als Schnittstelle (Binding) zwischen SolarForecast und der FANN‑Bibliothek dient.&lt;br /&gt;
&lt;br /&gt;
* AI::FANN ist die Brücke, über die unser Prognosesystem mit FANN kommuniziert.&lt;br /&gt;
* es ermöglicht dem System:&lt;br /&gt;
::* Trainingsdaten an FANN zu übergeben&lt;br /&gt;
::* ein neuronales Netz zu erzeugen&lt;br /&gt;
::* das Training zu steuern&lt;br /&gt;
::* das fertige Modell zu speichern und später für Prognosen zu nutzen&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Voraussetzungen ====&lt;br /&gt;
&lt;br /&gt;
===== Installation der FANN‑Library (Linux) ===== &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt-get update &amp;amp;&amp;amp; sudo apt-get upgrade&lt;br /&gt;
sudo apt-get install gcc&lt;br /&gt;
sudo apt-get install libfann-dev libfann2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RPM‑basierte Systeme:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo dnf install fann-devel&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
RPM‑basierte Systeme sind Linux‑Distributionen, die das Paketformat RPM (Red Hat Package Manager) verwenden.&lt;br /&gt;
&lt;br /&gt;
Typische RPM‑basierte Linux‑Distributionen:&lt;br /&gt;
* Red Hat Enterprise Linux (RHEL)&lt;br /&gt;
* CentOS / CentOS Stream&lt;br /&gt;
* Fedora&lt;br /&gt;
* openSUSE / SUSE Linux Enterprise&lt;br /&gt;
* Rocky Linux&lt;br /&gt;
* AlmaLinux&lt;br /&gt;
* Mageia&lt;br /&gt;
&lt;br /&gt;
===== Installation der FANN‑Library (Windows) ===== &lt;br /&gt;
&lt;br /&gt;
* der Installations- bzw. Erstellungsprozess der dll ist [https://fann.sourceforge.net/reference/x26.html hier] beschrieben &lt;br /&gt;
* fann.dll in PATH oder FHEM‑Verzeichnis kopieren  &lt;br /&gt;
* Perl‑Installation muss DLL laden können&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Installation des Perl‑Moduls AI::FANN ===== &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cpan install AI::FANN&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auf Debian Linux Systemen kann das Modul auch mit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt-get install libai-fann-perl &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
installiert werden.&lt;br /&gt;
&lt;br /&gt;
Alternativ kann natürlich auch cpanm oder der [https://wiki.fhem.de/wiki/Meta#Der_FHEM_Installer FHEM Installer] verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Bestandteile der Machine-Learning (ML)‑Pipeline ====&lt;br /&gt;
&lt;br /&gt;
===== Datenaufbereitung ===== &lt;br /&gt;
&lt;br /&gt;
Die Datenaufbereitung ist der wichtigste Schritt jeder ML‑Pipeline, da sie die Qualität der Eingabedaten sicherstellt.&lt;br /&gt;
Schlechte oder unskalierte Daten führen fast immer zu schlechten Modellen.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Normalisierung / Skalierung&#039;&#039;&#039;  &lt;br /&gt;
:- ML‑Modelle benötigen Eingabewerte in vergleichbaren Größenordnungen.&lt;br /&gt;
:- Beispiel: PV‑Leistung (0–10 000 W) vs. Uhrzeit (0–23).&lt;br /&gt;
:- Ohne Normalisierung würden große Werte die kleinen dominieren.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Feature‑Engineering&#039;&#039;&#039;  &lt;br /&gt;
: Aus Rohdaten werden zusätzliche Merkmale erzeugt, die Muster besser sichtbar machen:&lt;br /&gt;
::- Lags: Verbrauch der letzten Minuten/Stunden&lt;br /&gt;
::- Deltas: Änderungen gegenüber vorherigen Zeitpunkten&lt;br /&gt;
::- Zeitmerkmale: Stunde, Wochentag, Feiertag&lt;br /&gt;
::- PV‑Prognosen: erwartete Erzeugung als Einflussfaktor&lt;br /&gt;
::- Saisonale Merkmale: Sommer/Winter, Temperatur&lt;br /&gt;
::- Semantik (Erstellung von Interaktionen)&lt;br /&gt;
::- Rolling‑Statistics&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
📊 &#039;&#039;Rolling‑Statistics&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
„Rolling“ bedeutet, dass die Kennzahlen nicht einmalig über den gesamten Datensatz berechnet werden, sondern gleitend über ein Zeitfenster (z. B. 24 h, 7 Tage, 100 Samples). So werden Trends, Drift, Modellverschlechterung oder saisonale Muster besser erkannt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Integration zusätzlicher Verbraucher&#039;&#039;&#039;&lt;br /&gt;
: Wärmepumpen oder E‑Autos erzeugen starke, unregelmäßige Peaks. &lt;br /&gt;
: Diese können als zusätzliche Features einfließen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Es wird umgesetzt:&#039;&#039;&#039;&lt;br /&gt;
* ✔ Normalisierung auf physikalische Grenzen (PV‑Maximalleistung, Hausverbrauchs‑Maxima)&lt;br /&gt;
* ✔ Feature‑Engineering wie Lags, Deltas, Rolling‑Statistics, Zeitmerkmale, PV/PV-Prognosen als Input und weitere Semantik&lt;br /&gt;
* ✔ Optionale Zusatzlasten (WP/EV)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Trainingsdaten‑Split ===== &lt;br /&gt;
&lt;br /&gt;
Der Split trennt Daten in Trainingsdaten (zum Lernen) und Validierungsdaten (zur Qualitätskontrolle).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Training&#039;&#039;&#039;  &lt;br /&gt;
: Das Modell lernt Muster aus historischen Daten.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Validierung&#039;&#039;&#039;  &lt;br /&gt;
: Das Modell wird auf Daten getestet, die es nicht gesehen hat.&lt;br /&gt;
: Dadurch erkennt man Overfitting.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Shuffling&#039;&#039;&#039;  &lt;br /&gt;
: Durchmischen der Daten, um Reihenfolgeeffekte zu vermeiden.&lt;br /&gt;
: Besonders wichtig bei Zeitreihen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Es wird umgesetzt:&#039;&#039;&#039;&lt;br /&gt;
* ✔ Training/Validierung‑Split&lt;br /&gt;
* ✔ Shuffling je nach Einstellung von aiControl-&amp;gt;aiConShuffleMode&lt;br /&gt;
* ✔ Shuffle‑Perioden während des Trainings&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Netzarchitektur ===== &lt;br /&gt;
&lt;br /&gt;
Die Architektur bestimmt, wie das neuronale Netz aufgebaut ist.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Inputs&#039;&#039;&#039;  &lt;br /&gt;
: Anzahl der Merkmale (Features), die das Modell erhält.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Hidden Layers&#039;&#039;&#039;  &lt;br /&gt;
: Anzahl und Größe der verdeckten Schichten bestimmen, wie komplexe Muster erkannt werden können.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Output Layer&#039;&#039;&#039;  &lt;br /&gt;
: bei SolarForecast: 1 Wert = Verbrauchsprognose (Wh).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Es wird umgesetzt:&#039;&#039;&#039;&lt;br /&gt;
* ✔ Dynamische Input‑Anzahl je nach aktivierten Features&lt;br /&gt;
* ✔ Konfigurierbare Hidden Layers (z. B. 80‑40‑20)&lt;br /&gt;
* ✔ 1 Output‑Neuron&lt;br /&gt;
* ✔ Konfigurierbare Aktivierungsfunktionen&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Training ===== &lt;br /&gt;
&lt;br /&gt;
Hier werden die Gewichte des Netzes angepasst, um Fehler zu minimieren.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Trainingsalgorithmus&#039;&#039;&#039;&lt;br /&gt;
: RPROP: stabil, robust&lt;br /&gt;
: INCREMENTAL: schneller, aber empfindlicher&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lernrate (Learning Rate)&#039;&#039;&#039;  &lt;br /&gt;
: Wie stark Gewichte pro Schritt angepasst werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Momentum&#039;&#039;&#039;  &lt;br /&gt;
: Glättet die Lernbewegung, verhindert Zickzack‑Verhalten.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Steepness&#039;&#039;&#039;  &lt;br /&gt;
: Steuert die Empfindlichkeit der Aktivierungsfunktion.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Shuffle‑Perioden&#039;&#039;&#039;  &lt;br /&gt;
: Wie oft die Trainingsdaten neu gemischt werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Early‑Stopping&#039;&#039;&#039;  &lt;br /&gt;
: Training wird beendet, wenn Validierungsfehler nicht mehr sinkt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Es wird umgesetzt:&#039;&#039;&#039;&lt;br /&gt;
* ✔ RPROP und INCREMENTAL&lt;br /&gt;
* ✔ Learning Rate, Momentum, Steepness konfigurierbar&lt;br /&gt;
* ✔ Shuffle‑Perioden&lt;br /&gt;
* ✔ Early‑Stopping über Validierungsfehler&lt;br /&gt;
* ✔ Mehrere Trainingsläufe (Runs) zur Modellselektion&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Modellselektion und Fehlerevaluierung ===== &lt;br /&gt;
&lt;br /&gt;
Hier wird entschieden, welches Modell am Ende verwendet wird. &lt;br /&gt;
Die Ergebnisse des Trainings werden während des Traininglaufs fortlaufend überwacht und die Einhaltung von intern vorgegebenen Kennzahlen von einem Retrain-Guard überprüft. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Evaluation&#039;&#039;&#039;&lt;br /&gt;
* MAE, MAPE, RMSE, R²&lt;br /&gt;
* BitFail&lt;br /&gt;
* Bias/Slope&lt;br /&gt;
* P95/P99&lt;br /&gt;
&lt;br /&gt;
📈 &#039;&#039;Fehlermaße: MAE, MAPE, RMSE, R²&#039;&#039;  &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;MAE&#039;&#039;&#039; – Mean Absolute Error (durchschnittlicher absoluter Fehler) &lt;br /&gt;
::: MAE=1/𝑛∑∣𝑦−𝑦&amp;lt;sup&amp;gt;^&amp;lt;/sup&amp;gt;∣&lt;br /&gt;
* &#039;&#039;&#039;MAPE&#039;&#039;&#039; – Mean Absolute Percentage Error (prozentualer Fehler)&lt;br /&gt;
::: MAPE=100/𝑛∑∣(𝑦−𝑦&amp;lt;sup&amp;gt;^&amp;lt;/sup&amp;gt;)/𝑦∣&lt;br /&gt;
::* Achtung: &#039;&#039;&#039;problematisch bei kleinen oder Null‑Werten&#039;&#039;&#039; (klassisch bei Verbrauchsdaten nachts).&lt;br /&gt;
* &#039;&#039;&#039;RMSE&#039;&#039;&#039; – Root Mean Squared Error (Quadratischer Fehler, stärker empfindlich für Ausreißer)&lt;br /&gt;
::* gut, wenn große Fehler besonders kritisch sind&lt;br /&gt;
* &#039;&#039;&#039;R²&#039;&#039;&#039; – Bestimmtheitsmaß (Anteil der Varianz, den das Modell erklärt)&lt;br /&gt;
::: 𝑅&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;=1−(SSE/SST)&lt;br /&gt;
::* 1.0 = perfekt, 0 = nicht besser als Mittelwert, &amp;lt;0 = schlechter als Mittelwert&lt;br /&gt;
* &#039;&#039;&#039;P95 / P99&#039;&#039;&#039; (Quantile) - Quantile beschreiben, wie groß der Fehler in den schlechtesten X % der Fälle ist.&lt;br /&gt;
::* &#039;&#039;&#039;P95:&#039;&#039;&#039; 95 % der Fehler liegen darunter → die schlechtesten 5 % sind größer&lt;br /&gt;
::* &#039;&#039;&#039;P99:&#039;&#039;&#039; 99 % der Fehler liegen darunter → zeigt Extremfehler&lt;br /&gt;
* &#039;&#039;&#039;Bias / Slope&#039;&#039;&#039; (Regression‑Diagnostik) - Diese beiden Werte stammen aus einer linearen Regression zwischen &#039;&#039;&#039;Vorhersage&#039;&#039;&#039; und &#039;&#039;&#039;Ist‑Wert&#039;&#039;&#039;.&lt;br /&gt;
::* Diese beiden Werte sind extrem hilfreich, um Modell‑Drift oder fehlerhafte Normalisierung zu erkennen.&lt;br /&gt;
::* Slope - Ideal: 1.0&lt;br /&gt;
:::* &amp;lt; 1 → Modell unterschätzt hohe Werte&lt;br /&gt;
:::* &amp;gt;= 1 → Modell überschätzt hohe Werte&lt;br /&gt;
:::* zeigt systematische Skalierungsfehler&lt;br /&gt;
::* Bias - Ideal: 0&lt;br /&gt;
:::* positiv → Modell sagt im Schnitt zu wenig vorher&lt;br /&gt;
:::* negativ → Modell sagt im Schnitt zu viel vorher&lt;br /&gt;
:::* zeigt systematische Verschiebung&lt;br /&gt;
* &#039;&#039;&#039;BitFail&#039;&#039;&#039;&lt;br /&gt;
::* FANN verwendet „BitFail“ als Zählwert, wie viele Ausgaben eines Samples „falsch“ sind. Ein Output gilt als falsch, wenn der Fehler größer ist als ein definierter BitFail‑Schwellwert (z. B. 0.35).&lt;br /&gt;
::* Bei Regressionen ist BitFail weniger aussagekräftig, aber:&lt;br /&gt;
:::- es zeigt, wie viele Samples „deutlich daneben“ liegen.&lt;br /&gt;
:::- gut zur schnellen Qualitätskontrolle während des Trainings.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird die geforderte Güte nicht erreicht, initiiert der Guard eine Wiederholung des Trainings bis zu einer maximalen Anzahl von Durchläufen.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Bestes Modell speichern&#039;&#039;&#039;  &lt;br /&gt;
: Das Modell mit dem niedrigsten Validierungsfehler wird ausgewählt.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Verwendung nur des besten Modells&#039;&#039;&#039;  &lt;br /&gt;
: Schlechtere Modelle werden verworfen.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Trainingsmodus ohne Prognose&#039;&#039;&#039;  &lt;br /&gt;
: Nützlich, wenn man nur trainieren, aber noch nicht prognostizieren möchte.&lt;br /&gt;
: einschalten mit aiControl -&amp;gt;aiConActivate=2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Es wird umgesetzt:&#039;&#039;&#039;&lt;br /&gt;
* ✔ Monitoring mit Fehlerevaluierung&lt;br /&gt;
* ✔ bestes Modell wird automatisch gespeichert&lt;br /&gt;
* ✔ Prognosen basieren ausschließlich auf dem besten Modell&lt;br /&gt;
* ✔ Trainingsmodus only möglich (aiConActivate=2)&lt;br /&gt;
* ✔ Ausgabe detaillierter Trainingsmetriken&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Einstellbare Parameter über &#039;attr &amp;lt;Name&amp;gt; aiControl&#039; ====&lt;br /&gt;
&lt;br /&gt;
Die Einstellung von &#039;&#039;&#039;aiConActivate&#039;&#039;&#039;, &#039;&#039;&#039;aiConAlpha&#039;&#039;&#039; und &#039;&#039;&#039;aiConTrainStart&#039;&#039;&#039; wirken sofort, alle anderen Parameter werden erst beim nächsten Trainingslauf wirksam.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConActivate&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Wert !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| 0 || KI deaktiviert&lt;br /&gt;
|-&lt;br /&gt;
| 1 || KI aktiviert (Standard)&lt;br /&gt;
|-&lt;br /&gt;
| 2 || Trainingsmodus aktiv, die KI-Prognose ist deaktiviert. Es wird maximal eine Trainingswiederholung ausgeführt.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
* 1 ab 2000–3000 verfügbaren Datensätzen (siehe get &amp;lt;Name&amp;gt; valDecTree aiRawData), bei WP/EV &amp;gt; 5000&lt;br /&gt;
* Der Trainingsmodus dient dazu verschiedene Einstellungen testen zu können. Zur Zeitersparnis wird maximal eine Trainingswiederholung ausgeführt, unabhängig von der Güte des Trainingsergebisses&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConAlpha&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Mit diesem Parameter kann ein Hybridergebnis aus klassischen (Legacy‑)Prognosen und durch die KI ermittelten Prognosewerten erzeugt werden. Das Hybridergebnis wird durch eine prozentuale Mischung beider Resultate erstellt.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Wert !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| 0 || die KI-Ergebnisse werden nicht verwendet, nur Legacy Werte gehen in das finale Ergebnis ein&lt;br /&gt;
|-&lt;br /&gt;
| 0.x || die KI-Ergebnisse gehen zu 0.x * 100%, die Legacy Werte zu (1-0.x) * 100% in die finale Prognose ein &lt;br /&gt;
|-&lt;br /&gt;
| 1 || es werden ausschließlich KI-Ergebnisse verwendet, Legacy Werte gehen nicht in das finale Ergebnis ein&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
* 1 wenn die Genauigkeit der KI-Prognose überzeugend ist, ansonsten kann ein Mix aus KI und Legacy-Prognose hergestellt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConTrainStart&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Legt fest, wann das Modul ein atomatisches Erst- bzw. Folgetraining durchführt. Im Standard erfolgt das Training alle 7 Tage.&lt;br /&gt;
&lt;br /&gt;
Format: `&amp;lt;Tage&amp;gt;:&amp;lt;Stunde&amp;gt;`, z. B. `7:3`.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt; &lt;br /&gt;
* 7–14 Tage für normale Haushalte  &lt;br /&gt;
* 3–5 Tage bei WP/EV&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConActFunc&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Funktion !! Eigenschaften&lt;br /&gt;
|-&lt;br /&gt;
| SIGMOID || + bewährt, stabil, gut für kontinuierliche, monotone Zusammenhänge&lt;br /&gt;
– kann bei großen Inputs saturieren, aber bei Verbrauchsprognose meistens gut&lt;br /&gt;
|-&lt;br /&gt;
| GAUSSIAN || + gut für glatte Muster &lt;br /&gt;
– schlecht für harte Peaks (EV, Trockner), kann „vergessen“ und saturieren&lt;br /&gt;
|-&lt;br /&gt;
| ELLIOT || + schnellere, numerisch robustere Approximation von Sigmoid/Tanh, weniger Rechenaufwand &lt;br /&gt;
+ oft etwas „härter“ in der Reaktion, kann Peaks besser durchreichen &amp;lt;br&amp;gt;&lt;br /&gt;
– immer noch S‑förmig, also keine Wunderwaffe gegen komplett unmodellierte EV‑Ereignisse&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt; &lt;br /&gt;
* SIGMOID oder SIGMOID_SYMMETRIC als Standard&lt;br /&gt;
* bei allen weiteren Aktivierungsfunktionen kommt es auf den Versuch an&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConHiddenLayers&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Typ !! Beispiel !! Eigenschaften&lt;br /&gt;
|-&lt;br /&gt;
| klein || 50‑25 || schnell, weniger genau&lt;br /&gt;
|-&lt;br /&gt;
| mittel || 64‑32 || guter Kompromiss&lt;br /&gt;
|-&lt;br /&gt;
| tief || 64‑32‑16 / 80‑40‑20 || erkennt komplexe Muster&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
* &amp;lt; 3000 verfügbaren Datensätzen → `50-25`  &lt;br /&gt;
* 3000–8000 verfügbaren Datensätzen → `64-32`  &lt;br /&gt;
* &amp;gt; 8000 verfügbaren Datensätzen oder WP/EV → `80-40-20`&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConLearnRate&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Wert !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| 0.001 || sehr stabil, langsam&lt;br /&gt;
|-&lt;br /&gt;
| 0.005 || guter Kompromiss&lt;br /&gt;
|-&lt;br /&gt;
| 0.01–0.05 || schnell, aber instabil&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
* 0.005, bei WP/EV 0.001&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConBitFailLimit&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Das Bit‑Fail‑Limit bestimmt, &#039;&#039;&#039;ab welcher Abweichung zwischen Prognose und echtem Wert&#039;&#039;&#039; ein Trainingspunkt als „Fehler“ gezählt wird.&lt;br /&gt;
Ein kleinerer Wert macht das Training &#039;&#039;&#039;strenger&#039;&#039;&#039;, ein größerer Wert macht es &#039;&#039;&#039;toleranter&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;kleineres Limit → Modell versucht Peaks stärker zu treffen&#039;&#039;&#039; → kann instabil werden, besonders mit INCREMENTAL&lt;br /&gt;
* &#039;&#039;&#039;größeres Limit → Modell glättet stärker&#039;&#039;&#039; → robuster, aber weniger peak‑sensitiv&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Wert !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| kleineres Limit (0.10–0.25) || Das Modell versucht Peaks und schnelle Änderungen genauer zu treffen, kann aber instabiler werden.&lt;br /&gt;
|-&lt;br /&gt;
| mittleres Limit (0.25–0.35) || Gute Balance zwischen Genauigkeit und Stabilität. Empfohlener Startbereich.&lt;br /&gt;
|-&lt;br /&gt;
| größeres Limit (0.35–0.50) || Das Modell wird robuster gegen Ausreißer und Rauschen, reagiert aber weniger stark auf Spitzenlasten.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
🌪️ &#039;&#039;&#039;Was bedeutet „verrauschter Haushalt“?&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Ein Haushalt gilt als „verrauscht“, wenn der Stromverbrauch viele kleine, unregelmäßige Schwankungen hat, die nicht durch klare Muster (z. B. PV, Wärmepumpe, feste Tagesabläufe) erklärbar sind.&lt;br /&gt;
Dazu gehören spontane Gerätewechsel, impulsartige Lasten oder allgemein unruhige Verbrauchsprofile.&lt;br /&gt;
&lt;br /&gt;
Für solche Haushalte ist ein höheres Bit‑Fail‑Limit sinnvoll, weil das Modell dadurch robuster wird und nicht versucht, jede kleine Zufallsschwankung exakt vorherzusagen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
* versuche deinen Haushalt gemäß der oben beschriebenen Rauscheigenschaft einzuordnen und entscheide dann, ob ein Training unterhalb oder oberhalb des Defaultwertes (0.35) bei dir sinnvoll sein könnte. Bleibe dann bei der Einstellung die bei dir die besten Ergebnisse liefert. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConMomentum&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bereich !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| 0.2 || reagiert direkt, schwankt stärker&lt;br /&gt;
|-&lt;br /&gt;
| 0.5–0.8 || stabil, guter Kompromiss&lt;br /&gt;
|-&lt;br /&gt;
| 0.9 || sehr stark geglättet&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
* 0.5, bei WP/EV 0.7–0.8&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConShuffleMode&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Wert !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| 0 || chronologisch&lt;br /&gt;
|-&lt;br /&gt;
| 1 || chronologischer Split + Shuffle&lt;br /&gt;
|-&lt;br /&gt;
| 2 || vollständiges Shuffle&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt; &lt;br /&gt;
* 2, bei saisonalen Mustern 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConShufflePeriod&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Wert !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| 10 || viel Variation&lt;br /&gt;
|-&lt;br /&gt;
| 15–20 || stabiler Kompromiss&lt;br /&gt;
|-&lt;br /&gt;
| &amp;gt;20 || Gefahr von Overfitting&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
* 10, bei großen Datensätzen 15–20&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConSteepness&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bereich !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;0.4 || starke Glättung&lt;br /&gt;
|-&lt;br /&gt;
| 0.5 || Standard&lt;br /&gt;
|-&lt;br /&gt;
| &amp;gt;0.7 || schärfere Muster&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt; &lt;br /&gt;
* 0.9, bei glattem Verbrauch 0.5&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConTrainAlgo&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Algorithmus !! Eigenschaften&lt;br /&gt;
|-&lt;br /&gt;
| RPROP || stabil, wenig Parameter&lt;br /&gt;
|-&lt;br /&gt;
| INCREMENTAL || schneller, empfindlicher&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt; &lt;br /&gt;
* RPROP bei WP/EV  &lt;br /&gt;
* INCREMENTAL bei einfachen Profilen&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;aiConProfile&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die folgenden Profile bestimmen, welche Verbrauchslogiken und Semantiken im Modell aktiviert werden. Sie beeinflussen, wie stark das Modell auf typische Haushaltsaktivitäten, PV‑Erzeugung und Wärmepumpenverhalten reagiert.&lt;br /&gt;
&lt;br /&gt;
Damit Nutzer das passende Profil wählen können, sind die Profile hier verständlich beschrieben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Profil !! Eigenschaften&lt;br /&gt;
|-&lt;br /&gt;
| v1_common || Dieses Profil bildet den typischen menschlichen Tagesrhythmus ab:&lt;br /&gt;
* Morgenaktivität (Aufstehen, Geräte an)&lt;br /&gt;
* Mittagsaktivität (Kochen, Haushalt)&lt;br /&gt;
* Abendaktivität (Kochen, Licht, Geräte)&lt;br /&gt;
* Später Abend (Geräte gehen aus)&lt;br /&gt;
* Wochenendverhalten&lt;br /&gt;
* Tagesmuster vom Vortag&lt;br /&gt;
* Grundlast nachts&lt;br /&gt;
&lt;br /&gt;
Es nutzt Zeitstruktur, saisonale Muster, Wetter und Verbrauchsdynamik — aber &#039;&#039;&#039;keine PV‑ oder Wärmepumpenlogik&#039;&#039;&#039;. &amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Empfohlen für:&#039;&#039;&#039; &lt;br /&gt;
Haushalte mit reinem Stromverbrauch ohne besondere Geräte und wenig PV Einfluß, z.B. mit kleiner Balkon PV-Anlage.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| v1_common_active || Für &#039;&#039;&#039;Haushalte mit stark ausgeprägten Aktivitätsmustern&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Wie &#039;&#039;v1_common&#039;&#039;, aber mit stärkerer Betonung auf:&lt;br /&gt;
* Verbrauchssprüngen&lt;br /&gt;
* Trendbrüchen&lt;br /&gt;
* Volatilität (z. B. Kochen, Gerätewechsel)&lt;br /&gt;
* Wiederkehrenden Peaks&lt;br /&gt;
&lt;br /&gt;
Dieses Profil reagiert sensibler auf &#039;&#039;&#039;kurzfristige Verbrauchsdynamik&#039;&#039;&#039;. &amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Empfohlen für:&#039;&#039;&#039;  &lt;br /&gt;
Haushalte mit unregelmäßigen oder dynamischen Verbrauchsprofilen (z.B. viele Geräte, Homeoffice, Familien).&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| v1_common_pv || Für &#039;&#039;&#039;Haushalte mit PV-getriebenen Verbrauchern&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Erweitert &#039;&#039;v1_common&#039;&#039; um PV‑Semantik:&lt;br /&gt;
* PV‑Erzeugung + Tageszeit&lt;br /&gt;
* PV‑Drop‑Erkennung (Wolke → Lastabfall)&lt;br /&gt;
* PV‑abhängige Verbrauchsverschiebung&lt;br /&gt;
* PV‑Mittagsspitzen‑Verstärker&lt;br /&gt;
* PV‑Temperatur‑Interaktionen (Heizung, Batterie, Geräteverhalten)&lt;br /&gt;
&lt;br /&gt;
Das Modell versteht, dass Haushalte &#039;&#039;&#039;mittags anders verbrauchen&#039;&#039;&#039;, wenn PV‑Strom verfügbar ist. &amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Empfohlen für:&#039;&#039;&#039;  &lt;br /&gt;
Haushalte mit größerer PV‑Anlage, aber ohne Wärmepumpe.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| v1_common_active_pv || Für &#039;&#039;&#039;Haushalte mit dynamisch PV-getriebenen Verbrauchsverhalten&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Kombiniert: &lt;br /&gt;
* Dynamik‑Semantik aus v1_common_active&lt;br /&gt;
* PV‑Semantik aus v1_common_pv&lt;br /&gt;
&lt;br /&gt;
Dieses Profil erkennt:&lt;br /&gt;
* spontane Peaks bei PV‑Überschuss&lt;br /&gt;
* Verbrauchssprünge + PV‑Erzeugung&lt;br /&gt;
* Trendverstärker mittags&lt;br /&gt;
* PV‑Drop‑Reaktionen&lt;br /&gt;
* Volatilität + PV‑Interaktionen&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Empfohlen für:&#039;&#039;&#039;  &lt;br /&gt;
PV‑Haushalte mit aktiven Verbrauchern (z.B. Kochen, Waschmaschine, Trockner usw.).&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| v1_heatpump || Für &#039;&#039;&#039;Haushalte mit Wärmepumpe (ohne dominante PV)&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Aktiviert die komplette Wärmepumpen‑Semantik:&lt;br /&gt;
* Heizmodus, Kühlmodus&lt;br /&gt;
* Warmwasser (morgens/abends, Zyklen, Kaltstart)&lt;br /&gt;
* Frostschutz&lt;br /&gt;
* Temperaturtrends&lt;br /&gt;
* Effizienzindikatoren (COP‑Proxy)&lt;br /&gt;
* Heiz‑/Kühlbedarf&lt;br /&gt;
* Temperaturdeltas und -historie&lt;br /&gt;
&lt;br /&gt;
Das Modell versteht typische WP‑Verbrauchsmuster:&lt;br /&gt;
* morgens und abends Heizen&lt;br /&gt;
* Warmwasserzyklen&lt;br /&gt;
* Frostschutz nachts&lt;br /&gt;
* Reaktion auf Temperaturstürze&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Empfohlen für:&#039;&#039;&#039;  &lt;br /&gt;
Haushalte mit Wärmepumpe, aber ohne dominante PV.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| v1_heatpump_pv || Für &#039;&#039;&#039;Wärmepumpen‑Haushalte mit dominanter PV&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Kombiniert:&lt;br /&gt;
* Wärmepumpen‑Semantik&lt;br /&gt;
* PV‑Semantik&lt;br /&gt;
* PV‑Warmwasser‑Boost&lt;br /&gt;
* PV‑Mittagsverschiebung&lt;br /&gt;
* PV‑abhängige Heiz-/WW‑Strategien&lt;br /&gt;
* Das Modell erkennt:&lt;br /&gt;
* PV‑Überschuss → Warmwasser&lt;br /&gt;
* PV‑Erzeugung → Heiz-/Kühlverhalten&lt;br /&gt;
* PV‑Drop → Lastabfall&lt;br /&gt;
* PV + Kälte → Heizspitzen&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Empfohlen für:&#039;&#039;&#039;  &lt;br /&gt;
Haushalte mit Wärmepumpe und dominanter PV‑Anlage.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| v1_heatpump_active_pv || Für &#039;&#039;&#039;Wärmepumpe + PV + dynamisches Verbrauchsverhalten&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Das umfassendste Profil. Es kombiniert:&lt;br /&gt;
* Wärmepumpen‑Semantik&lt;br /&gt;
* PV‑Semantik&lt;br /&gt;
* Dynamik‑Semantik (Trend, Volatilität, Peaks)&lt;br /&gt;
* Spezial‑Booster (z. B. heatpump_boost_special, pv_mittag_peak_boost_special)&lt;br /&gt;
&lt;br /&gt;
Dieses Profil erkennt:&lt;br /&gt;
* spontane Verbrauchssprünge&lt;br /&gt;
* WP‑Zyklen + PV‑Überschuss&lt;br /&gt;
* Trendbrüche + Temperaturdeltas&lt;br /&gt;
* dynamische Mittagspeaks&lt;br /&gt;
* komplexe Interaktionen zwischen PV, WP und menschlichem Verhalten&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Empfohlen für:&#039;&#039;&#039;  &lt;br /&gt;
Haushalte mit Wärmepumpe, PV und sehr aktivem Verbrauchsverhalten.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|  || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Best‑Practice:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Die oben angegebenen Profileigenschaften beschreiben die implementierten Verstärkungen bzw. auch Abschwächungen zur Unterstützung des Lernprozesses der künstlichen Intelligenz. Teste Trainings mit unterschiedlichen Profilen und wähle das Profil mit dem die besten Ergebnisse erzielt werden. Beginne mit dem Profil welches wahrscheinlich am Besten zu deinem Haushalt passen könnte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Integration von Umwelt- und Kontextfaktoren in die Prognose ====&lt;br /&gt;
&lt;br /&gt;
Die Verbrauchscharakteristik eines Haushalts wird nicht nur durch die eingesetzten elektrischen Geräte bestimmt, sondern auch durch verschiedene systemische Einflussfaktoren, darunter:&lt;br /&gt;
&lt;br /&gt;
* Anwesenheit bzw. Abwesenheit der Bewohner&lt;br /&gt;
* Außentemperaturen&lt;br /&gt;
* Abweichungen vom üblichen Tagesmuster, z.B. durch Feiertage oder Urlaubszeiten&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einbindung von Sensoren und Kontextdaten&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Außentemperatursensoren, Windsensoren sowie Geräte zur Anwesenheits- oder Bewegungsdetektion werden im Attribut &#039;&#039;&#039;setupEnvironment&#039;&#039;&#039; hinterlegt. Die dafür erforderliche Syntax ist in der Online‑Hilfe des Moduls dokumentiert. SolarForecast nutzt diese Informationen, um Verbrauchsprognosen an reale Rahmenbedingungen anzupassen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die erfassten Umweltdaten sind Momentanwerte, die – sofern sie eine ausreichende Dynamik aufweisen – auf das in SolarForecast verwendete Stundenraster normiert oder geglättet werden.&lt;br /&gt;
&lt;br /&gt;
::* &#039;&#039;&#039;Außentemperaturen:&#039;&#039;&#039; Temperaturen ändern sich vergleichsweise langsam und werden daher direkt übernommen. Ist kein Temperatursensor definiert, wird die Temperatur des verwendeten Wetterdienstes genutzt.&lt;br /&gt;
::* &#039;&#039;&#039;Anwesenheit:&#039;&#039;&#039; Für jede Stunde wird der Anwesenheitsstatus anhand des überwiegenden Zustands innerhalb dieser Stunde bestimmt.&lt;br /&gt;
::::- &#039;&#039;&#039;Beispiel:&#039;&#039;&#039; Verlassen die Bewohner das Haus erst zehn Minuten vor Ende der Stunde, würde eine reine Momentaufnahme den Status &#039;&#039;„abwesend“&#039;&#039; speichern. Da dies sachlich nicht zutrifft, wird der überwiegende Status der Stunde bewertet und gespeichert.&lt;br /&gt;
::* &#039;&#039;&#039;Windgeschwindigkeit:&#039;&#039;&#039; Zur Bewertung der Windverhältnisse werden zwei geglättete Windgeschwindigkeiten berechnet - eine &#039;&#039;&#039;schnelle&#039;&#039;&#039; und eine &#039;&#039;&#039;langsame&#039;&#039;&#039; Komponente. Beide verwenden &#039;&#039;&#039;exponentielles Glätten&#039;&#039;&#039;, bei dem neue Messwerte stärker gewichtet werden als ältere.&lt;br /&gt;
:::: - &#039;&#039;&#039;Fast (10 Minuten):&#039;&#039;&#039; Reagiert schnell auf kurzfristige Änderungen, z. B. durch vorbeiziehende Wolken.&lt;br /&gt;
:::: - &#039;&#039;&#039;Slow (40 Minuten):&#039;&#039;&#039; Spiegelt die Großwetterlage bzw. den längerfristigen Trend wider.&lt;br /&gt;
:::: Die Glättung erfolgt nach dem Prinzip: &lt;br /&gt;
:::::: &amp;lt;code&amp;gt; neuer Wert = α · aktueller Messwert + (1 − α) · vorheriger geglätteter Wert &amp;lt;/code&amp;gt;&lt;br /&gt;
:::: wobei &amp;lt;code&amp;gt;α&amp;lt;/code&amp;gt; abhängig von der jeweiligen Zeitkonstante berechnet wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Feiertage und Urlaubszeiten&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Berücksichtigung von Feiertagen und Urlaub wird das in FHEM etablierte Verfahren über [https://fhem.de/commandref_DE.html#holiday holiday]-Devices verwendet.&lt;br /&gt;
Dazu werden die entsprechenden holiday‑Devices im globalen Attribut &#039;&#039;holiday2we&#039;&#039; registriert. SolarForecast liest die dort eingetragenen holiday‑Devices aus und übernimmt die darin definierten Daten (z.B. gesetzliche Feiertage, benutzerdefinierte freie Tage oder Urlaubszeiträume).&lt;br /&gt;
&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Das Training durchführen und produktiv setzen (Best Practice Ansatz) ====&lt;br /&gt;
&lt;br /&gt;
Sind alle [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Voraussetzungen|Voraussetzungen]] erfüllt, kann das Verbauchsprognose-Modell trainiert und – sofern das Ergebnis überzeugt – für den Produktivbetrieb aktiviert werden. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1️⃣ &#039;&#039;&#039;Training‑Only‑Modus aktivieren&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für das initiale Training wird FANN im &#039;&#039;Training‑Only‑Modus&#039;&#039; aktiviert:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; aiControl aiConActivate=2&lt;br /&gt;
&lt;br /&gt;
In diesem Modus kann das Modell beliebig oft trainiert, bewertet und durch Anpassung der [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Einstellbare_Parameter_über_&#039;attr_&amp;lt;Name&amp;gt;_aiControl|Steuerungsparameter]] optimiert werden – ohne dass die produktive Prognose beeinflusst wird. Es kann jederzeit ein neues Training gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wer den Trainingsablauf und die internen Prüfungen live verfolgen möchte, aktiviert zusätzlich:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; ctrlDebug aiProcess&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2️⃣ &#039;&#039;&#039;Training starten&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Mit der FANN-Aktivierung durch aiControl aiConActivate=2 (oder 1) werden automatisch sinnvolle &#039;&#039;&#039;Standardparameter&#039;&#039;&#039; für FANN gesetzt. Für den Einstieg empfiehlt es sich, zunächst mit diesen Defaults zu trainieren und Änderungen an Parametern schrittweise vorzunehmen, neu zu trainieren und die Veränderungen im Ergebnis zu bewerten. Als Hilfestellung gibt es dazu einen separaten [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Auswertung_der_Trainingskennwerte|Abschnitt]]. &lt;br /&gt;
&lt;br /&gt;
Das Training wird manuell gestartet mit:&lt;br /&gt;
&lt;br /&gt;
 set &amp;lt;Name&amp;gt; aiDecTree runConTrain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Ein bereits laufendes Training wird durch einen erneuten Start mit &#039;&#039;runConTrain&#039;&#039; automatisch abgebrochen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ein laufendes Training kann jederzeit manuell beendet werden:&lt;br /&gt;
&lt;br /&gt;
 set &amp;lt;Name&amp;gt; aiDecTree stopConTrain&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3️⃣ &#039;&#039;&#039;Wie das Training intern abläuft&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Der Trainingsprozess wird vollständig durch die interne Steuerungslogik des Moduls geführt:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Ein Trainingsjob umfasst &#039;&#039;&#039;bis zu 6 Trainingswiederholungen&#039;&#039;&#039;, jede mit &#039;&#039;&#039;maximal 15000&#039;&#039;&#039; Epochen.&lt;br /&gt;
* Ein &#039;&#039;&#039;Snapshot‑Guard&#039;&#039;&#039; überwacht kontinuierlich die Modellverbesserung und speichert bessere Modelle als Best Snapshot.&lt;br /&gt;
* Ein integrierter &#039;&#039;&#039;Early‑Stopping‑Mechanismus&#039;&#039;&#039; beendet Trainingsläufe, die sich nicht weiter verbessern.&lt;br /&gt;
* Ein interner &#039;&#039;&#039;Retrain‑Indikator&#039;&#039;&#039; bewertet den besten Snapshot. Ein &#039;&#039;&#039;Quality Gate&#039;&#039;&#039; entscheidet, ob ein weiterer Retrain durchgeführt wird.&lt;br /&gt;
* Die Anzahl der Retrains wird &#039;&#039;&#039;adaptiv&#039;&#039;&#039; anhand interner Kriterien bestimmt.&lt;br /&gt;
* Mit aktiviertem Debug‑Modus werden alle Entscheidungen im Log dokumentiert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der gesamte Prozess läuft in einem &#039;&#039;&#039;Nebenprozess&#039;&#039;&#039;, um FHEM nicht zu blockieren.&lt;br /&gt;
Je nach Hardware, Datenmenge und Parametern kann das Training sehr lange dauern – im Extremfall mehrere Stunden. Ein CPU‑Kern kann dabei dauerhaft zu 100 % ausgelastet sein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
4️⃣ &#039;&#039;&#039;Ergebnis bewerten&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Nach Abschluss des Trainings sollte das Ergebnis &#039;&#039;&#039;[[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Auswertung_der_Trainingskennwerte|manuell bewertet]]&#039;&#039;&#039; werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtige Hinweise:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
* Auch bei &#039;&#039;&#039;nicht perfekten Kennzahlen&#039;&#039;&#039; lohnt sich eine visuelle Prüfung.&lt;br /&gt;
* Auch bei &#039;&#039;&#039;zu perfekten Kennzahlen&#039;&#039;&#039; ist Vorsicht geboten – dies kann auf Overfitting hindeuten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
5️⃣ &#039;&#039;&#039;Modell produktiv setzen&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zur visuellen Begutachtung und für den Produktivbetrieb wird das trainierte Modell aktiviert:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; aiControl aiConActivate=1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Im nächsten Zyklus des Moduls (siehe &#039;attr ... plantControl cycleInterval&#039;) erscheinen die KI‑Prognosen in der Balkengrafik, sofern diese Ansicht aktiviert ist. Wenn die Prognose zufriedenstellend ist, bleibt das Modell aktiv. Falls nicht, kann jederzeit wieder in den &#039;&#039;Training‑Only&#039;&#039;‑Modus gewechselt werden, um Parameter anzupassen und erneut zu trainieren.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
6️⃣ &#039;&#039;&#039;Automatisches (Re)Training&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Bei aktivem FANN‑Modus (aiConActivate=1 oder 2) wird automatisch alle &#039;&#039;&#039;7 Tage um 03:00 Uhr&#039;&#039;&#039; ein Retraining durchgeführt.&lt;br /&gt;
Der Zeitpunkt kann angepasst werden:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; aiControl aiConTrainStart ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
7️⃣ &#039;&#039;&#039;Hybrid‑Modus&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Das Modul unterstützt einen &#039;&#039;&#039;Hybrid‑Modus&#039;&#039;&#039;, bei dem KI‑Prognosen mit den klassischen (Legacy‑)Prognosen gewichtet kombiniert werden. &lt;br /&gt;
Gesteuert wird dieser Modus über:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; aiControl aiConAlpha &amp;lt;Wert&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ein höherer Wert von [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Einstellbare_Parameter_über_&#039;attr_&amp;lt;Name&amp;gt;_aiControl&#039;|&#039;&#039;&#039;aiConAlpha&#039;&#039;&#039;]] bedeutet stärkere Gewichtung der KI‑Prognose.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
8️⃣ &#039;&#039;&#039;Debug‑Log&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für eine detaillierte Nachvollziehbarkeit des Trainingsprozesses kann der Debug‑Modus aktiviert werden.&lt;br /&gt;
Im Debug‑Log protokolliert das Modul sämtliche Schritte der Trainingslogik, darunter:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Start und Ende einzelner Trainingsläufe&lt;br /&gt;
* Verbesserungen der Modellgüte&lt;br /&gt;
* Snapshot‑Updates&lt;br /&gt;
* Early‑Stopping‑Ereignisse&lt;br /&gt;
* Entscheidungen des Quality Gates&lt;br /&gt;
* Auslösung von Retrains&lt;br /&gt;
* Abschlussbewertung des besten Modells&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dies erleichtert sowohl die Diagnose ungewöhnlicher Trainingsverläufe als auch die Bewertung, ob Parameteranpassungen sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible mw-collapsed&amp;quot;&amp;gt;&lt;br /&gt;
Ein &#039;&#039;&#039;auszugsweises Beispiel&#039;&#039;&#039; eines Trainingslogs -&amp;gt; &amp;lt;div class=&amp;quot;mw-collapsible-content&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
2026.01.01 15:40:06.690 1: SolCast DEBUG&amp;gt; First attempt 0 with Seed=407496&lt;br /&gt;
2026.01.01 15:40:06.696 1: SolCast DEBUG&amp;gt; AI FANN Training started with Params:&lt;br /&gt;
num input datasets=7931, &lt;br /&gt;
training algo=FANN_TRAIN_INCREMENTAL, &lt;br /&gt;
output AF=LINEAR, &lt;br /&gt;
hidden AF=SIGMOID, &lt;br /&gt;
hidden Neurons=80,40,20, &lt;br /&gt;
hidden steepness=0.9, &lt;br /&gt;
Epoches=15000, &lt;br /&gt;
mse_error=0.001, &lt;br /&gt;
learning rate=0.00500, &lt;br /&gt;
learning momentum=0.5, &lt;br /&gt;
Data sharing=split after shuffle of training data and use AI internal shuffle (Train=6344, Test=1586), &lt;br /&gt;
Data shuffle=2 (period=10)&lt;br /&gt;
2026.01.01 15:40:06.818 1: SolCast DEBUG&amp;gt; Epoche 1: Train MSE=0.001532, Val MSE=0.002521, Val MAE=0.028206, Val MedAE=0.020769, Bit_Fail=5 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 15:40:07.534 1: SolCast DEBUG&amp;gt; Epoche 8: Train MSE=0.001472, Val MSE=0.002520, Val MAE=0.028199, Val MedAE=0.020764, Bit_Fail=5 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 15:40:13.541 1: SolCast DEBUG&amp;gt; Epoche 67: Train MSE=0.001477, Val MSE=0.002518, Val MAE=0.026941, Val MedAE=0.018749, Bit_Fail=5 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 15:40:13.748 1: SolCast DEBUG&amp;gt; Epoche 69: Train MSE=0.001476, Val MSE=0.002517, Val MAE=0.026928, Val MedAE=0.018728, Bit_Fail=5 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
...&lt;br /&gt;
2026.01.01 15:40:21.048 1: SolCast DEBUG&amp;gt; Epoche 140: Train MSE=0.001181, Val MSE=0.002253, Val MAE=0.023585, Val MedAE=0.012176, Bit_Fail=5 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 15:40:27.191 1: SolCast DEBUG&amp;gt; Epoche 200: Train MSE=0.001181, Val MSE=0.001860, Val MAE=0.022984, Val MedAE=0.012926, Bit_Fail=4&lt;br /&gt;
2026.01.01 15:40:27.704 1: SolCast DEBUG&amp;gt; Epoche 205: Train MSE=0.000982, Val MSE=0.001821, Val MAE=0.022794, Val MedAE=0.012760, Bit_Fail=4 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 15:40:29.356 1: SolCast DEBUG&amp;gt; Epoche 221: Train MSE=0.000894, Val MSE=0.001654, Val MAE=0.021991, Val MedAE=0.012736, Bit_Fail=4 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
...&lt;br /&gt;
2026.01.01 15:40:30.508 1: SolCast DEBUG&amp;gt; Epoche 232: Train MSE=0.000806, Val MSE=0.001516, Val MAE=0.020531, Val MedAE=0.011495, Bit_Fail=4 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 15:40:30.615 1: SolCast DEBUG&amp;gt; Epoche 233: Train MSE=0.000797, Val MSE=0.001498, Val MAE=0.020435, Val MedAE=0.011480, Bit_Fail=2 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 15:40:30.722 1: SolCast DEBUG&amp;gt; Epoche 234: Train MSE=0.000787, Val MSE=0.001479, Val MAE=0.020336, Val MedAE=0.011380, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 15:40:30.829 1: SolCast DEBUG&amp;gt; Epoche 235: Train MSE=0.000777, Val MSE=0.001460, Val MAE=0.020232, Val MedAE=0.011321, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
...&lt;br /&gt;
2026.01.01 15:40:34.103 1: SolCast DEBUG&amp;gt; Epoche 266: Train MSE=0.000347, Val MSE=0.000621, Val MAE=0.015564, Val MedAE=0.010886, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 15:40:34.209 1: SolCast DEBUG&amp;gt; Epoche 267: Train MSE=0.000336, Val MSE=0.000598, Val MAE=0.015326, Val MedAE=0.010661, Bit_Fail=0 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 15:40:34.322 1: SolCast DEBUG&amp;gt; Epoche 268: Train MSE=0.000325, Val MSE=0.000576, Val MAE=0.015095, Val MedAE=0.010564, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 15:40:34.431 1: SolCast DEBUG&amp;gt; Epoche 269: Train MSE=0.000314, Val MSE=0.000555, Val MAE=0.014870, Val MedAE=0.010315, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
...&lt;br /&gt;
2026.01.01 15:45:53.259 1: SolCast DEBUG&amp;gt; Epoche 3300: Train MSE=0.000188, Val MSE=0.000286, Val MAE=0.011095, Val MedAE=0.007725, Bit_Fail=0&lt;br /&gt;
2026.01.01 15:46:00.439 1: SolCast DEBUG&amp;gt; Early stopping bei Epoche 3368 (no improvement since 2000 epochs)&lt;br /&gt;
2026.01.01 15:46:00.439 1: === Snapshot-Statistik ===&lt;br /&gt;
2026.01.01 15:46:00.440 1: Metric-Improvement Snapshots: 67 (letzte Epoche: 1368)&lt;br /&gt;
2026.01.01 15:46:00.440 1: Bit-Improvement Snapshots:    5 (letzte Epoche: 267)&lt;br /&gt;
2026.01.01 15:46:00.441 1: Bit-Tradeoff Snapshots:       0 (letzte Epoche: 0)&lt;br /&gt;
2026.01.01 15:46:00.443 1: SolCast DEBUG&amp;gt; Best Snapshot reloaded from Epoche 1368: Train MSE=0.000188, Val MSE=0.000286, Val MAE=0.010789, Val MedAE=0.006938, Bit_Fail=0,&lt;br /&gt;
2026.01.01 15:46:00.444 1: SolCast DEBUG&amp;gt; Run Validation Test with 20% of Input data ...&lt;br /&gt;
2026.01.01 15:46:00.475 1: SolCast DEBUG&amp;gt; Validation finished - Best Training MSE=0.000188, Validation MSE=0.000286, Validation Bit_Fail=0&lt;br /&gt;
2026.01.01 15:46:00.476 1: SolCast DEBUG&amp;gt; Retrain check -&amp;gt; &lt;br /&gt;
-- In Normalization Space: -- &lt;br /&gt;
Train MSE=0.000188 &lt;br /&gt;
Val MSE=0.000286 &lt;br /&gt;
Val Mean=0.0002908456 &lt;br /&gt;
VAL/TRAIN MSE Ratio=1.525656 (limit=2.5) &lt;br /&gt;
Diff=0.000099 (limit=0.005) &lt;br /&gt;
ValStd=0.0000052738 (limit=7.27113936211133e-05) &lt;br /&gt;
-- At Original Scale: -- &lt;br /&gt;
MAE=96.4264081498789 &lt;br /&gt;
RMSE/MAE=1.5680 (limit=1.5) &lt;br /&gt;
Slope=0.846171 (limit=0.7 .. 1.3) &lt;br /&gt;
Bias=104.79 (limit=+-48.2132040749395) &lt;br /&gt;
R2=0.886437100872621 &lt;br /&gt;
P95=283.1830 (limit=385.705632599516) &lt;br /&gt;
P99=538.2559 (limit=771.411265199031) &lt;br /&gt;
-- Robustness Indicators: -- &lt;br /&gt;
RMSE relative=24 (limit=20) &lt;br /&gt;
BitFail=0 (limit=5) &lt;br /&gt;
BitFailRate=0.0000 (limit=0.1) &lt;br /&gt;
-&amp;gt; Retrain&lt;br /&gt;
&amp;lt;/pre&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;div class=&amp;quot;mw-collapsible mw-collapsed&amp;quot;&amp;gt;&lt;br /&gt;
Ein &#039;&#039;&#039;komplettes Beispiel mit 3 Wiederholungen&#039;&#039;&#039; eines Trainingslogs -&amp;gt; &amp;lt;div class=&amp;quot;mw-collapsible-content&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
2026.01.01 18:03:45.037 1: SolCast DEBUG&amp;gt; AI FANN Training for Consumption Forecast BlockingCall PID &amp;quot;813631&amp;quot; with Timeout 86400 s started&lt;br /&gt;
2026.01.01 18:03:46.046 1: SolCast DEBUG&amp;gt; AI FANN - There are 503 Records skipped due to incomplete or invalid data. Index: &lt;br /&gt;
2025013115, 2025020401, 2025020414, 2025020415, 2025020416, 2025021813, 2025021816, 2025021913, 2025021914, 2025021915, 2025022013, 2025022316, 2025030216, 2025030310, 2025030315, 2025030316, 2025030416, 2025030511, 2025030512, 2025030516, 2025030517, 2025030610, 2025030611, 2025030612, 2025030616, 2025030710, 2025030711, 2025030712, 2025030713, 2025030716, 2025030810, 2025030910, 2025030916, 2025030917, 2025031010, 2025031114, 2025031519, 2025031609, 2025031709, 2025031710, 2025031716, 2025031717, 2025031810, 2025031811, 2025031814, 2025031815, 2025031816, 2025031817, 2025031909, 2025031910, 2025031911, 2025031915, 2025031916, 2025031917, 2025032010, 2025032011, 2025032014, 2025032015, 2025032016, 2025032017, 2025032110, 2025032114, 2025032115, 2025032116, 2025032117, 2025032209, 2025032210, 2025032211, 2025032214, 2025032215, 2025032814, 2025032815, 2025032817, 2025033003, 2025040211, 2025040212, 2025040215, 2025040216, 2025040217, 2025040314, 2025040315, 2025040316, 2025040317, 2025040318, 2025040410, 2025040411, 2025040413, 2025040414, 2025040418, 2025040510, 2025040517, 2025040518, 2025040612, 2025040617, 2025040618, 2025040711, 2025040811, 2025040812, 2025040813, 2025041017, 2025041018, 2025041110, 2025041111, 2025041216, 2025041217, 2025041218, 2025041312, 2025041316, 2025041317, 2025041417, 2025041418, 2025041611, 2025041617, 2025041618, 2025042017, 2025042018, 2025042115, 2025042117, 2025042118, 2025042218, 2025042609, 2025042610, 2025042611, 2025042612, 2025042617, 2025042618, 2025042710, 2025042711, 2025042712, 2025042714, 2025042715, 2025042717, 2025042718, 2025042810, 2025042811, 2025042813, 2025042814, 2025042817, 2025042818, 2025042911, 2025042913, 2025042914, 2025042917, 2025042918, 2025050110, 2025050111, 2025050114, 2025050117, 2025050118, 2025050210, 2025050211, 2025050213, 2025050518, 2025050610, 2025050611, 2025050614, 2025050617, 2025050618, 2025050706, 2025050707, 2025050708, 2025050810, 2025050812, 2025050816, 2025050817, 2025050910, 2025050911, 2025050912, 2025050917, 2025050918, 2025051009, 2025051010, 2025051011, 2025051012, 2025051017, 2025051018, 2025051109, 2025051210, 2025051211, 2025051212, 2025051213, 2025051214, 2025051218, 2025051310, 2025051313, 2025051314, 2025051317, 2025051318, 2025051411, 2025051413, 2025051414, 2025051418, 2025051510, 2025051610, 2025051611, 2025051710, 2025051713, 2025051916, 2025052010, 2025052011, 2025052017, 2025052018, 2025052111, 2025052113, 2025052114, 2025052115, 2025052118, 2025052211, 2025052409, 2025052410, 2025052416, 2025052417, 2025052609, 2025052616, 2025052617, 2025052618, 2025052817, 2025052910, 2025052911, 2025052917, 2025053010, 2025053013, 2025053017, 2025053018, 2025053109, 2025053110, 2025053111, 2025053112, 2025053113, 2025053115, 2025053117, 2025060210, 2025060215, 2025060217, 2025060310, 2025060312, 2025060317, 2025060318, 2025060513, 2025060517, 2025060609, 2025060610, 2025060618, 2025060710, 2025060711, 2025060712, 2025060713, 2025060811, 2025060812, 2025060816, 2025060817, 2025060818, 2025060909, 2025060910, 2025060911, 2025060912, 2025060913, 2025060917, 2025060918, 2025061015, 2025061016, 2025061109, 2025061114, 2025061117, 2025061118, 2025061119, 2025061209, 2025061210, 2025061211, 2025061212, 2025061213, 2025061214, 2025061215, 2025061217, 2025061218, 2025061309, 2025061310, 2025061311, 2025061312, 2025061313, 2025061314, 2025061315, 2025061317, 2025061318, 2025061319, 2025061410, 2025061411, 2025061413, 2025061414, 2025061417, 2025061418, 2025061710, 2025061713, 2025061714, 2025061717, 2025061718, 2025061724, 2025062010, 2025062011, 2025062013, 2025062014, 2025062017, 2025062018, 2025062109, 2025062110, 2025062111, 2025062112, 2025062114, 2025062117, 2025062118, 2025062209, 2025062210, 2025062211, 2025062212, 2025062213, 2025062214, 2025062217, 2025062218, 2025062309, 2025062310, 2025062311, 2025062317, 2025062318, 2025062409, 2025062410, 2025062411, 2025062818, 2025062911, 2025062913, 2025062918, 2025063009, 2025063011, 2025063013, 2025063014, 2025063017, 2025063018, 2025070110, 2025070111, 2025070112, 2025070113, 2025070117, 2025070118, 2025070210, 2025070211, 2025070212, 2025070213, 2025070217, 2025070218, 2025070318, 2025070410, 2025070411, 2025070412, 2025070417, 2025070418, 2025070510, 2025070511, 2025070512, 2025070610, 2025070611, 2025070615, 2025070717, 2025070810, 2025071013, 2025071017, 2025071112, 2025071113, 2025071117, 2025071311, 2025071318, 2025071410, 2025071411, 2025071812, 2025071818, 2025071910, 2025071911, 2025071912, 2025071913, 2025071918, 2025072009, 2025072510, 2025072514, 2025073110, 2025073118, 2025080118, 2025080210, 2025080310, 2025080410, 2025080417, 2025080418, 2025080616, 2025080617, 2025080715, 2025080716, 2025080717, 2025080718, 2025080917, 2025080918, 2025081015, 2025081016, 2025081017, 2025081018, 2025081115, 2025081116, 2025081117, 2025081118, 2025081120, 2025081121, 2025081122, 2025081123, 2025081124, 2025081215, 2025081216, 2025081217, 2025081315, 2025081316, 2025081317, 2025081318, 2025081415, 2025081416, 2025081417, 2025081418, 2025081516, 2025081517, 2025081617, 2025081816, 2025081817, 2025081818, 2025081915, 2025081916, 2025081917, 2025082015, 2025082016, 2025082017, 2025082018, 2025082115, 2025082116, 2025082117, 2025082416, 2025082516, 2025082517, 2025082518, 2025082519, 2025082612, 2025082613, 2025082614, 2025082618, 2025082716, 2025082717, 2025083110, 2025083111, 2025083113, 2025083118, 2025090110, 2025090215, 2025090311, 2025090317, 2025090411, 2025090414, 2025090417, 2025090517, 2025090610, 2025090611, 2025090612, 2025090618, 2025090710, 2025090711, 2025090713, 2025090714, 2025090718, 2025090810, 2025090813, 2025090910, 2025090911, 2025091217, 2025091816, 2025091817, 2025091915, 2025091916, 2025091917, 2025092014, 2025092015, 2025092016, 2025092017, 2025092113, 2025092115, 2025092315, 2025092316, 2025092417, 2025092910, 2025092911, 2025092912, 2025092917, 2025093011, 2025093012, 2025093013, 2025093017, 2025100316, 2025100317, 2025110320, 2025122222, 2025122223, 2025122224, 2025122510&lt;br /&gt;
2026.01.01 18:03:46.940 1: SolCast - DBG F[7300]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.942 1: SolCast - DBG F[7301]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.944 1: SolCast - DBG F[7302]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.945 1: SolCast - DBG F[7303]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.947 1: SolCast - DBG F[7304]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.949 1: SolCast - DBG F[7305]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.951 1: SolCast - DBG F[7306]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.953 1: SolCast - DBG F[7307]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.954 1: SolCast - DBG F[7308]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.956 1: SolCast - DBG F[7309]: lag1=0.001 lag2=0.001 lag24=0.001 d1p=0.000 d1n=0.000 rollstd=0.000 up=0 down=0 upS=0.000 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.958 1: SolCast - DBG F[7310]: lag1=0.002 lag2=0.001 lag24=0.002 d1p=0.036 d1n=0.000 rollstd=0.000 up=1 down=0 upS=0.036 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.960 1: SolCast - DBG F[7311]: lag1=0.026 lag2=0.002 lag24=0.008 d1p=0.004 d1n=0.000 rollstd=0.033 up=0 down=0 upS=0.004 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.962 1: SolCast - DBG F[7312]: lag1=0.029 lag2=0.026 lag24=0.012 d1p=0.000 d1n=0.008 rollstd=0.044 up=0 down=1 upS=0.000 downS=0.008 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.963 1: SolCast - DBG F[7313]: lag1=0.023 lag2=0.029 lag24=0.016 d1p=0.011 d1n=0.000 rollstd=0.045 up=1 down=0 upS=0.011 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.965 1: SolCast - DBG F[7314]: lag1=0.031 lag2=0.023 lag24=0.018 d1p=0.000 d1n=0.003 rollstd=0.044 up=0 down=0 upS=0.000 downS=0.003 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.967 1: SolCast - DBG F[7315]: lag1=0.028 lag2=0.031 lag24=0.017 d1p=0.002 d1n=0.000 rollstd=0.036 up=0 down=0 upS=0.002 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.968 1: SolCast - DBG F[7316]: lag1=0.030 lag2=0.028 lag24=0.008 d1p=0.000 d1n=0.002 rollstd=0.009 up=0 down=0 upS=0.000 downS=0.002 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.970 1: SolCast - DBG F[7317]: lag1=0.028 lag2=0.030 lag24=0.002 d1p=0.000 d1n=0.005 rollstd=0.009 up=0 down=1 upS=0.000 downS=0.005 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.974 1: SolCast - DBG F[7318]: lag1=0.025 lag2=0.028 lag24=0.002 d1p=0.005 d1n=0.000 rollstd=0.010 up=1 down=0 upS=0.005 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:46.976 1: SolCast - DBG F[7319]: lag1=0.028 lag2=0.025 lag24=0.001 d1p=0.008 d1n=0.000 rollstd=0.007 up=1 down=0 upS=0.008 downS=0.000 vol=0 pvX=0 break=0&lt;br /&gt;
2026.01.01 18:03:47.013 1: SolCast DEBUG&amp;gt; First attempt 0 with Seed=439288&lt;br /&gt;
2026.01.01 18:03:47.024 1: SolCast DEBUG&amp;gt; AI FANN Training started with Params:&lt;br /&gt;
num input datasets=7314, &lt;br /&gt;
training algo=FANN_TRAIN_INCREMENTAL, &lt;br /&gt;
output AF=LINEAR, &lt;br /&gt;
hidden AF=SIGMOID, &lt;br /&gt;
hidden Neurons=80,40,20, &lt;br /&gt;
hidden steepness=0.9, &lt;br /&gt;
Epoches=15000, &lt;br /&gt;
mse_error=0.001, &lt;br /&gt;
learning rate=0.00500, &lt;br /&gt;
learning momentum=0.7, &lt;br /&gt;
Data sharing=split after shuffle of training data and use AI internal shuffle (Train=5851, Test=1462), &lt;br /&gt;
Data shuffle=2 (period=10)&lt;br /&gt;
2026.01.01 18:03:47.208 1: SolCast DEBUG&amp;gt; Epoche 1: Train MSE=0.002194, Val MSE=0.002834, Val MAE=0.031901, Val MedAE=0.027985, Bit_Fail=2 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:03:47.528 1: SolCast DEBUG&amp;gt; Epoche 3: Train MSE=0.002192, Val MSE=0.002833, Val MAE=0.031892, Val MedAE=0.027975, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:03:54.175 1: SolCast DEBUG&amp;gt; Epoche 48: Train MSE=0.001736, Val MSE=0.002765, Val MAE=0.029706, Val MedAE=0.016374, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:02.843 1: SolCast DEBUG&amp;gt; Epoche 100: Train MSE=0.001736, Val MSE=0.001509, Val MAE=0.026824, Val MedAE=0.022443, Bit_Fail=1&lt;br /&gt;
2026.01.01 18:04:07.181 1: SolCast DEBUG&amp;gt; Epoche 127: Train MSE=0.000623, Val MSE=0.001033, Val MAE=0.022203, Val MedAE=0.017074, Bit_Fail=1 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:04:07.341 1: SolCast DEBUG&amp;gt; Epoche 128: Train MSE=0.000611, Val MSE=0.001012, Val MAE=0.021994, Val MedAE=0.017013, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:07.519 1: SolCast DEBUG&amp;gt; Epoche 129: Train MSE=0.000599, Val MSE=0.000990, Val MAE=0.021783, Val MedAE=0.016793, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:07.994 1: SolCast DEBUG&amp;gt; Epoche 131: Train MSE=0.000577, Val MSE=0.000943, Val MAE=0.021456, Val MedAE=0.016655, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:08.185 1: SolCast DEBUG&amp;gt; Epoche 132: Train MSE=0.000566, Val MSE=0.000922, Val MAE=0.021240, Val MedAE=0.016463, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:08.344 1: SolCast DEBUG&amp;gt; Epoche 133: Train MSE=0.000554, Val MSE=0.000901, Val MAE=0.021025, Val MedAE=0.016355, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:08.508 1: SolCast DEBUG&amp;gt; Epoche 134: Train MSE=0.000543, Val MSE=0.000881, Val MAE=0.020809, Val MedAE=0.016328, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:08.684 1: SolCast DEBUG&amp;gt; Epoche 135: Train MSE=0.000532, Val MSE=0.000860, Val MAE=0.020593, Val MedAE=0.016227, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:08.840 1: SolCast DEBUG&amp;gt; Epoche 136: Train MSE=0.000521, Val MSE=0.000841, Val MAE=0.020381, Val MedAE=0.016031, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:08.989 1: SolCast DEBUG&amp;gt; Epoche 137: Train MSE=0.000511, Val MSE=0.000822, Val MAE=0.020175, Val MedAE=0.015652, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:09.144 1: SolCast DEBUG&amp;gt; Epoche 138: Train MSE=0.000501, Val MSE=0.000803, Val MAE=0.019972, Val MedAE=0.015495, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:09.297 1: SolCast DEBUG&amp;gt; Epoche 139: Train MSE=0.000492, Val MSE=0.000786, Val MAE=0.019773, Val MedAE=0.015409, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:09.458 1: SolCast DEBUG&amp;gt; Epoche 140: Train MSE=0.000481, Val MSE=0.000777, Val MAE=0.019495, Val MedAE=0.015158, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:09.615 1: SolCast DEBUG&amp;gt; Epoche 141: Train MSE=0.000473, Val MSE=0.000760, Val MAE=0.019325, Val MedAE=0.015145, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:09.767 1: SolCast DEBUG&amp;gt; Epoche 142: Train MSE=0.000465, Val MSE=0.000745, Val MAE=0.019163, Val MedAE=0.015044, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:09.919 1: SolCast DEBUG&amp;gt; Epoche 143: Train MSE=0.000457, Val MSE=0.000730, Val MAE=0.019008, Val MedAE=0.015017, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:10.080 1: SolCast DEBUG&amp;gt; Epoche 144: Train MSE=0.000449, Val MSE=0.000716, Val MAE=0.018857, Val MedAE=0.014983, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:10.245 1: SolCast DEBUG&amp;gt; Epoche 145: Train MSE=0.000442, Val MSE=0.000702, Val MAE=0.018714, Val MedAE=0.014883, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:10.400 1: SolCast DEBUG&amp;gt; Epoche 146: Train MSE=0.000436, Val MSE=0.000690, Val MAE=0.018579, Val MedAE=0.014777, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:10.705 1: SolCast DEBUG&amp;gt; Epoche 148: Train MSE=0.000424, Val MSE=0.000667, Val MAE=0.018328, Val MedAE=0.014732, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:10.858 1: SolCast DEBUG&amp;gt; Epoche 149: Train MSE=0.000418, Val MSE=0.000656, Val MAE=0.018213, Val MedAE=0.014659, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:11.447 1: SolCast DEBUG&amp;gt; Epoche 153: Train MSE=0.000398, Val MSE=0.000655, Val MAE=0.017918, Val MedAE=0.014430, Bit_Fail=0 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:04:11.597 1: SolCast DEBUG&amp;gt; Epoche 154: Train MSE=0.000394, Val MSE=0.000648, Val MAE=0.017836, Val MedAE=0.014356, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:11.780 1: SolCast DEBUG&amp;gt; Epoche 155: Train MSE=0.000390, Val MSE=0.000641, Val MAE=0.017757, Val MedAE=0.014209, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:11.968 1: SolCast DEBUG&amp;gt; Epoche 156: Train MSE=0.000386, Val MSE=0.000635, Val MAE=0.017685, Val MedAE=0.014026, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:12.119 1: SolCast DEBUG&amp;gt; Epoche 157: Train MSE=0.000383, Val MSE=0.000629, Val MAE=0.017617, Val MedAE=0.013986, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:15.889 1: SolCast DEBUG&amp;gt; Epoche 180: Train MSE=0.000338, Val MSE=0.000530, Val MAE=0.017079, Val MedAE=0.013927, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:19.269 1: SolCast DEBUG&amp;gt; Epoche 200: Train MSE=0.000338, Val MSE=0.000535, Val MAE=0.016673, Val MedAE=0.013893, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:04:35.878 1: SolCast DEBUG&amp;gt; Epoche 290: Train MSE=0.000288, Val MSE=0.000524, Val MAE=0.016388, Val MedAE=0.013535, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:36.582 1: SolCast DEBUG&amp;gt; Epoche 293: Train MSE=0.000287, Val MSE=0.000523, Val MAE=0.016367, Val MedAE=0.013507, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:37.370 1: SolCast DEBUG&amp;gt; Epoche 296: Train MSE=0.000287, Val MSE=0.000522, Val MAE=0.016353, Val MedAE=0.013413, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:04:38.343 1: SolCast DEBUG&amp;gt; Epoche 300: Train MSE=0.000287, Val MSE=0.000500, Val MAE=0.016520, Val MedAE=0.014059, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:04:53.153 1: SolCast DEBUG&amp;gt; Epoche 360: Train MSE=0.000276, Val MSE=0.000498, Val MAE=0.016213, Val MedAE=0.013363, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:05:03.452 1: SolCast DEBUG&amp;gt; Epoche 400: Train MSE=0.000276, Val MSE=0.000492, Val MAE=0.016416, Val MedAE=0.013627, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:05:29.137 1: SolCast DEBUG&amp;gt; Epoche 500: Train MSE=0.000276, Val MSE=0.000500, Val MAE=0.016208, Val MedAE=0.013216, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:05:51.013 1: SolCast DEBUG&amp;gt; Epoche 600: Train MSE=0.000276, Val MSE=0.000500, Val MAE=0.016319, Val MedAE=0.012971, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:06:14.772 1: SolCast DEBUG&amp;gt; Epoche 700: Train MSE=0.000276, Val MSE=0.000511, Val MAE=0.016383, Val MedAE=0.013241, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:06:36.483 1: SolCast DEBUG&amp;gt; Epoche 800: Train MSE=0.000276, Val MSE=0.000509, Val MAE=0.016792, Val MedAE=0.013049, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:06:52.867 1: SolCast DEBUG&amp;gt; Epoche 900: Train MSE=0.000276, Val MSE=0.000495, Val MAE=0.015972, Val MedAE=0.012938, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:06:52.877 1: SolCast DEBUG&amp;gt; Epoche 900: Train MSE=0.000242, Val MSE=0.000495, Val MAE=0.015972, Val MedAE=0.012938, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:07:09.391 1: SolCast DEBUG&amp;gt; Epoche 1000: Train MSE=0.000242, Val MSE=0.000493, Val MAE=0.016187, Val MedAE=0.013015, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:07:14.202 1: SolCast DEBUG&amp;gt; Epoche 1027: Train MSE=0.000237, Val MSE=0.000491, Val MAE=0.015971, Val MedAE=0.012928, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:07:18.001 1: SolCast DEBUG&amp;gt; Epoche 1050: Train MSE=0.000234, Val MSE=0.000486, Val MAE=0.015890, Val MedAE=0.012757, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:07:18.455 1: SolCast DEBUG&amp;gt; Epoche 1053: Train MSE=0.000234, Val MSE=0.000485, Val MAE=0.015881, Val MedAE=0.012678, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:07:25.760 1: SolCast DEBUG&amp;gt; Epoche 1100: Train MSE=0.000234, Val MSE=0.000480, Val MAE=0.015846, Val MedAE=0.012669, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:07:25.766 1: SolCast DEBUG&amp;gt; Epoche 1100: Train MSE=0.000233, Val MSE=0.000480, Val MAE=0.015846, Val MedAE=0.012669, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:07:42.102 1: SolCast DEBUG&amp;gt; Epoche 1200: Train MSE=0.000233, Val MSE=0.000484, Val MAE=0.016233, Val MedAE=0.012505, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:07:43.824 1: SolCast DEBUG&amp;gt; Epoche 1210: Train MSE=0.000227, Val MSE=0.000470, Val MAE=0.015552, Val MedAE=0.012390, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:07:57.828 1: SolCast DEBUG&amp;gt; Epoche 1300: Train MSE=0.000227, Val MSE=0.000520, Val MAE=0.017539, Val MedAE=0.013492, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:08:14.430 1: SolCast DEBUG&amp;gt; Epoche 1400: Train MSE=0.000227, Val MSE=0.000460, Val MAE=0.016046, Val MedAE=0.012304, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:08:16.132 1: SolCast DEBUG&amp;gt; Epoche 1410: Train MSE=0.000222, Val MSE=0.000452, Val MAE=0.015408, Val MedAE=0.011884, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:08:17.883 1: SolCast DEBUG&amp;gt; Epoche 1420: Train MSE=0.000220, Val MSE=0.000443, Val MAE=0.015258, Val MedAE=0.011811, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:08:29.901 1: SolCast DEBUG&amp;gt; Epoche 1490: Train MSE=0.000218, Val MSE=0.000439, Val MAE=0.014983, Val MedAE=0.011569, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:08:30.803 1: SolCast DEBUG&amp;gt; Epoche 1496: Train MSE=0.000218, Val MSE=0.000438, Val MAE=0.014960, Val MedAE=0.011509, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:08:31.440 1: SolCast DEBUG&amp;gt; Epoche 1500: Train MSE=0.000218, Val MSE=0.000439, Val MAE=0.015419, Val MedAE=0.011971, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:08:47.448 1: SolCast DEBUG&amp;gt; Epoche 1600: Train MSE=0.000218, Val MSE=0.000454, Val MAE=0.016309, Val MedAE=0.012168, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:08:50.500 1: SolCast DEBUG&amp;gt; Epoche 1620: Train MSE=0.000214, Val MSE=0.000431, Val MAE=0.014770, Val MedAE=0.011218, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:09:03.800 1: SolCast DEBUG&amp;gt; Epoche 1700: Train MSE=0.000214, Val MSE=0.000439, Val MAE=0.015947, Val MedAE=0.012095, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:09:12.275 1: SolCast DEBUG&amp;gt; Epoche 1755: Train MSE=0.000210, Val MSE=0.000414, Val MAE=0.014646, Val MedAE=0.011210, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:09:19.335 1: SolCast DEBUG&amp;gt; Epoche 1800: Train MSE=0.000210, Val MSE=0.000427, Val MAE=0.015787, Val MedAE=0.011912, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:09:36.229 1: SolCast DEBUG&amp;gt; Epoche 1900: Train MSE=0.000210, Val MSE=0.000417, Val MAE=0.015680, Val MedAE=0.011996, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:09:45.972 1: SolCast DEBUG&amp;gt; Epoche 1960: Train MSE=0.000204, Val MSE=0.000388, Val MAE=0.014589, Val MedAE=0.011116, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:09:51.969 1: SolCast DEBUG&amp;gt; Epoche 2000: Train MSE=0.000204, Val MSE=0.000404, Val MAE=0.015606, Val MedAE=0.012356, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:09:53.511 1: SolCast DEBUG&amp;gt; Epoche 2010: Train MSE=0.000202, Val MSE=0.000386, Val MAE=0.014313, Val MedAE=0.011006, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:09:55.063 1: SolCast DEBUG&amp;gt; Epoche 2020: Train MSE=0.000201, Val MSE=0.000383, Val MAE=0.014131, Val MedAE=0.010774, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:10:08.287 1: SolCast DEBUG&amp;gt; Epoche 2100: Train MSE=0.000201, Val MSE=0.000380, Val MAE=0.014528, Val MedAE=0.011353, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:10:24.098 1: SolCast DEBUG&amp;gt; Epoche 2200: Train MSE=0.000201, Val MSE=0.000370, Val MAE=0.013946, Val MedAE=0.010416, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:10:24.104 1: SolCast DEBUG&amp;gt; Epoche 2200: Train MSE=0.000197, Val MSE=0.000370, Val MAE=0.013946, Val MedAE=0.010416, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:10:39.646 1: SolCast DEBUG&amp;gt; Epoche 2300: Train MSE=0.000197, Val MSE=0.000374, Val MAE=0.014907, Val MedAE=0.011753, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:10:56.682 1: SolCast DEBUG&amp;gt; Epoche 2400: Train MSE=0.000197, Val MSE=0.000356, Val MAE=0.013705, Val MedAE=0.010006, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:10:56.693 1: SolCast DEBUG&amp;gt; Epoche 2400: Train MSE=0.000192, Val MSE=0.000356, Val MAE=0.013705, Val MedAE=0.010006, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:11:12.550 1: SolCast DEBUG&amp;gt; Epoche 2500: Train MSE=0.000192, Val MSE=0.000375, Val MAE=0.015257, Val MedAE=0.012743, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:11:15.676 1: SolCast DEBUG&amp;gt; Epoche 2520: Train MSE=0.000191, Val MSE=0.000355, Val MAE=0.013591, Val MedAE=0.009674, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:11:17.824 1: SolCast DEBUG&amp;gt; Epoche 2531: Train MSE=0.000190, Val MSE=0.000346, Val MAE=0.013480, Val MedAE=0.009639, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:11:28.987 1: SolCast DEBUG&amp;gt; Epoche 2600: Train MSE=0.000190, Val MSE=0.000339, Val MAE=0.013649, Val MedAE=0.010530, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:11:45.115 1: SolCast DEBUG&amp;gt; Epoche 2700: Train MSE=0.000190, Val MSE=0.000354, Val MAE=0.014651, Val MedAE=0.011877, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:12:01.075 1: SolCast DEBUG&amp;gt; Epoche 2790: Train MSE=0.000186, Val MSE=0.000341, Val MAE=0.013362, Val MedAE=0.009487, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:12:02.671 1: SolCast DEBUG&amp;gt; Epoche 2800: Train MSE=0.000186, Val MSE=0.000333, Val MAE=0.013606, Val MedAE=0.010687, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:12:18.422 1: SolCast DEBUG&amp;gt; Epoche 2900: Train MSE=0.000186, Val MSE=0.000335, Val MAE=0.013448, Val MedAE=0.010124, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:12:35.464 1: SolCast DEBUG&amp;gt; Epoche 3000: Train MSE=0.000186, Val MSE=0.000327, Val MAE=0.013352, Val MedAE=0.010017, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:12:56.411 1: SolCast DEBUG&amp;gt; Epoche 3100: Train MSE=0.000186, Val MSE=0.000333, Val MAE=0.013996, Val MedAE=0.011160, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:13:10.994 1: SolCast DEBUG&amp;gt; Epoche 3162: Train MSE=0.000181, Val MSE=0.000328, Val MAE=0.013113, Val MedAE=0.009469, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:13:18.736 1: SolCast DEBUG&amp;gt; Epoche 3200: Train MSE=0.000181, Val MSE=0.000320, Val MAE=0.013393, Val MedAE=0.010591, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:13:39.675 1: SolCast DEBUG&amp;gt; Epoche 3300: Train MSE=0.000181, Val MSE=0.000319, Val MAE=0.013325, Val MedAE=0.010389, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:14:00.271 1: SolCast DEBUG&amp;gt; Epoche 3400: Train MSE=0.000181, Val MSE=0.000325, Val MAE=0.014006, Val MedAE=0.011521, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:14:22.409 1: SolCast DEBUG&amp;gt; Epoche 3500: Train MSE=0.000181, Val MSE=0.000344, Val MAE=0.014666, Val MedAE=0.012138, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:14:38.101 1: SolCast DEBUG&amp;gt; Epoche 3580: Train MSE=0.000177, Val MSE=0.000319, Val MAE=0.012991, Val MedAE=0.009430, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:14:42.467 1: SolCast DEBUG&amp;gt; Epoche 3600: Train MSE=0.000177, Val MSE=0.000314, Val MAE=0.013079, Val MedAE=0.010056, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:15:03.838 1: SolCast DEBUG&amp;gt; Epoche 3700: Train MSE=0.000177, Val MSE=0.000333, Val MAE=0.014308, Val MedAE=0.011807, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:15:16.053 2: HUEBridge: http request failed: read from http://192.168.2.7:80 timed out&lt;br /&gt;
2026.01.01 18:15:30.476 1: SolCast DEBUG&amp;gt; Epoche 3800: Train MSE=0.000177, Val MSE=0.000321, Val MAE=0.013020, Val MedAE=0.009413, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:15:45.037 1: SolCast DEBUG&amp;gt; Epoche 3870: Train MSE=0.000174, Val MSE=0.000317, Val MAE=0.012911, Val MedAE=0.009292, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:15:52.131 1: SolCast DEBUG&amp;gt; Epoche 3900: Train MSE=0.000174, Val MSE=0.000312, Val MAE=0.013464, Val MedAE=0.010556, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:16:12.390 1: SolCast DEBUG&amp;gt; Epoche 4000: Train MSE=0.000174, Val MSE=0.000320, Val MAE=0.013974, Val MedAE=0.011455, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:16:29.091 1: SolCast DEBUG&amp;gt; Epoche 4100: Train MSE=0.000174, Val MSE=0.000312, Val MAE=0.013592, Val MedAE=0.010912, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:16:52.505 1: SolCast DEBUG&amp;gt; Epoche 4200: Train MSE=0.000174, Val MSE=0.000302, Val MAE=0.012962, Val MedAE=0.010156, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:17:16.099 1: SolCast DEBUG&amp;gt; Epoche 4300: Train MSE=0.000174, Val MSE=0.000303, Val MAE=0.013023, Val MedAE=0.010334, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:17:31.066 1: openMeteo - Open-Meteo API server response: start_SSL https://api.open-meteo.com:443 timed out&lt;br /&gt;
2026.01.01 18:17:38.285 1: SolCast DEBUG&amp;gt; Epoche 4400: Train MSE=0.000174, Val MSE=0.000302, Val MAE=0.013197, Val MedAE=0.010550, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:17:52.429 1: SolCast DEBUG&amp;gt; Epoche 4460: Train MSE=0.000170, Val MSE=0.000311, Val MAE=0.012837, Val MedAE=0.009137, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:17:58.628 1: SolCast DEBUG&amp;gt; Epoche 4490: Train MSE=0.000170, Val MSE=0.000305, Val MAE=0.012794, Val MedAE=0.009134, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:18:01.453 1: SolCast DEBUG&amp;gt; Epoche 4500: Train MSE=0.000170, Val MSE=0.000301, Val MAE=0.012898, Val MedAE=0.009802, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:18:23.799 1: SolCast DEBUG&amp;gt; Epoche 4600: Train MSE=0.000170, Val MSE=0.000298, Val MAE=0.012957, Val MedAE=0.010201, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:18:39.811 1: SolCast DEBUG&amp;gt; Epoche 4700: Train MSE=0.000170, Val MSE=0.000301, Val MAE=0.013527, Val MedAE=0.011413, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:18:56.354 1: SolCast DEBUG&amp;gt; Epoche 4800: Train MSE=0.000170, Val MSE=0.000298, Val MAE=0.013255, Val MedAE=0.011018, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:19:12.392 1: SolCast DEBUG&amp;gt; Epoche 4900: Train MSE=0.000170, Val MSE=0.000295, Val MAE=0.013216, Val MedAE=0.010940, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:19:27.987 1: SolCast DEBUG&amp;gt; Epoche 5000: Train MSE=0.000170, Val MSE=0.000293, Val MAE=0.013073, Val MedAE=0.010728, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:19:32.327 1: SolCast DEBUG&amp;gt; Epoche 5030: Train MSE=0.000167, Val MSE=0.000297, Val MAE=0.012698, Val MedAE=0.009102, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:19:43.670 1: SolCast DEBUG&amp;gt; Epoche 5100: Train MSE=0.000167, Val MSE=0.000298, Val MAE=0.013300, Val MedAE=0.010884, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:19:59.190 1: SolCast DEBUG&amp;gt; Epoche 5200: Train MSE=0.000167, Val MSE=0.000294, Val MAE=0.013167, Val MedAE=0.010790, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:20:10.606 1: SolCast DEBUG&amp;gt; Epoche 5262: Train MSE=0.000166, Val MSE=0.000295, Val MAE=0.012677, Val MedAE=0.009089, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:20:16.409 1: SolCast DEBUG&amp;gt; Epoche 5300: Train MSE=0.000166, Val MSE=0.000292, Val MAE=0.013247, Val MedAE=0.011177, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:20:34.708 1: SolCast DEBUG&amp;gt; Epoche 5400: Train MSE=0.000166, Val MSE=0.000291, Val MAE=0.012964, Val MedAE=0.010392, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:20:57.206 1: SolCast DEBUG&amp;gt; Epoche 5500: Train MSE=0.000166, Val MSE=0.000288, Val MAE=0.012996, Val MedAE=0.010552, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:21:21.536 1: SolCast DEBUG&amp;gt; Epoche 5600: Train MSE=0.000166, Val MSE=0.000286, Val MAE=0.012927, Val MedAE=0.010610, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:21:43.826 1: SolCast DEBUG&amp;gt; Epoche 5700: Train MSE=0.000166, Val MSE=0.000284, Val MAE=0.012811, Val MedAE=0.010111, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:21:46.073 1: SolCast DEBUG&amp;gt; Epoche 5710: Train MSE=0.000164, Val MSE=0.000292, Val MAE=0.012617, Val MedAE=0.009052, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:22:05.636 1: SolCast DEBUG&amp;gt; Epoche 5800: Train MSE=0.000164, Val MSE=0.000311, Val MAE=0.013979, Val MedAE=0.012142, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:22:28.019 1: SolCast DEBUG&amp;gt; Epoche 5900: Train MSE=0.000164, Val MSE=0.000284, Val MAE=0.012679, Val MedAE=0.009654, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:22:44.531 1: SolCast DEBUG&amp;gt; Epoche 6000: Train MSE=0.000164, Val MSE=0.000333, Val MAE=0.014735, Val MedAE=0.013016, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:23:00.239 1: SolCast DEBUG&amp;gt; Epoche 6100: Train MSE=0.000164, Val MSE=0.000286, Val MAE=0.012652, Val MedAE=0.009522, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:23:16.145 1: SolCast DEBUG&amp;gt; Epoche 6200: Train MSE=0.000164, Val MSE=0.000283, Val MAE=0.012623, Val MedAE=0.009526, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:23:31.970 1: SolCast DEBUG&amp;gt; Epoche 6300: Train MSE=0.000164, Val MSE=0.000294, Val MAE=0.013520, Val MedAE=0.011589, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:23:48.995 1: SolCast DEBUG&amp;gt; Epoche 6400: Train MSE=0.000164, Val MSE=0.000290, Val MAE=0.013238, Val MedAE=0.011187, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:24:04.958 1: SolCast DEBUG&amp;gt; Epoche 6500: Train MSE=0.000164, Val MSE=0.000283, Val MAE=0.013087, Val MedAE=0.011112, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:24:20.473 1: SolCast DEBUG&amp;gt; Epoche 6600: Train MSE=0.000164, Val MSE=0.000291, Val MAE=0.012657, Val MedAE=0.009198, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:24:35.890 1: SolCast DEBUG&amp;gt; Epoche 6700: Train MSE=0.000164, Val MSE=0.000290, Val MAE=0.013459, Val MedAE=0.011749, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:24:52.891 1: SolCast DEBUG&amp;gt; Epoche 6800: Train MSE=0.000164, Val MSE=0.000289, Val MAE=0.013364, Val MedAE=0.011509, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:25:08.802 1: SolCast DEBUG&amp;gt; Epoche 6900: Train MSE=0.000164, Val MSE=0.000283, Val MAE=0.013144, Val MedAE=0.011185, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:25:24.371 1: SolCast DEBUG&amp;gt; Epoche 7000: Train MSE=0.000164, Val MSE=0.000278, Val MAE=0.012650, Val MedAE=0.009934, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:25:39.968 1: SolCast DEBUG&amp;gt; Epoche 7100: Train MSE=0.000164, Val MSE=0.000320, Val MAE=0.014405, Val MedAE=0.012857, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:25:56.650 1: SolCast DEBUG&amp;gt; Epoche 7200: Train MSE=0.000164, Val MSE=0.000281, Val MAE=0.013030, Val MedAE=0.011100, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:26:12.530 1: SolCast DEBUG&amp;gt; Epoche 7300: Train MSE=0.000164, Val MSE=0.000277, Val MAE=0.012556, Val MedAE=0.009580, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:26:28.387 1: SolCast DEBUG&amp;gt; Epoche 7400: Train MSE=0.000164, Val MSE=0.000275, Val MAE=0.012574, Val MedAE=0.009786, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:26:44.426 1: SolCast DEBUG&amp;gt; Epoche 7500: Train MSE=0.000164, Val MSE=0.000282, Val MAE=0.013197, Val MedAE=0.011348, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:27:00.108 1: SolCast DEBUG&amp;gt; Epoche 7600: Train MSE=0.000164, Val MSE=0.000279, Val MAE=0.012521, Val MedAE=0.009349, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:27:17.631 1: SolCast DEBUG&amp;gt; Epoche 7700: Train MSE=0.000164, Val MSE=0.000334, Val MAE=0.014836, Val MedAE=0.013130, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:27:19.201 1: SolCast DEBUG&amp;gt; Early stopping bei Epoche 7710 (no improvement since 2000 epochs)&lt;br /&gt;
2026.01.01 18:27:19.203 1: === Snapshot-Statistik ===&lt;br /&gt;
2026.01.01 18:27:19.206 1: Metric-Improvement Snapshots: 59 (letzte Epoche: 5710)&lt;br /&gt;
2026.01.01 18:27:19.208 1: Bit-Improvement Snapshots:    3 (letzte Epoche: 153)&lt;br /&gt;
2026.01.01 18:27:19.211 1: Bit-Tradeoff Snapshots:       0 (letzte Epoche: 0)&lt;br /&gt;
2026.01.01 18:27:19.222 1: SolCast DEBUG&amp;gt; Best Snapshot reloaded from Epoche 5710: Train MSE=0.000164, Val MSE=0.000292, Val MAE=0.012617, Val MedAE=0.009052, Bit_Fail=0,&lt;br /&gt;
2026.01.01 18:27:19.225 1: SolCast DEBUG&amp;gt; Run Validation Test with 20% of Input data ...&lt;br /&gt;
2026.01.01 18:27:19.269 1: SolCast DEBUG&amp;gt; Validation finished - Best Training MSE=0.000164, Validation MSE=0.000292, Validation Bit_Fail=0&lt;br /&gt;
2026.01.01 18:27:19.272 1: SolCast DEBUG&amp;gt; Retrain check -&amp;gt; &lt;br /&gt;
-- In Normalization Space: -- &lt;br /&gt;
Train MSE=0.000164 &lt;br /&gt;
Val MSE=0.000292 &lt;br /&gt;
Val Mean=0.0003006352 &lt;br /&gt;
VAL/TRAIN MSE Ratio=1.778317 (limit=2.5) &lt;br /&gt;
Diff=0.000128 (limit=0.005) &lt;br /&gt;
ValStd=0.0000223852 (limit=7.51588070934039e-05) &lt;br /&gt;
-- At Original Scale: -- &lt;br /&gt;
MAE=207.818584965433 &lt;br /&gt;
RMSE/MAE=1.3545 (limit=1.5) &lt;br /&gt;
Slope=0.930345 (limit=0.7 .. 1.3) &lt;br /&gt;
Bias=-1.81 (limit=+-103.909292482717) &lt;br /&gt;
R2=0.896675647742538 &lt;br /&gt;
P95=565.7317 (limit=831.274339861732) &lt;br /&gt;
P99=813.5925 (limit=1662.54867972346) &lt;br /&gt;
-- Robustness Indicators: -- &lt;br /&gt;
RMSE relative=60 (limit=20) &lt;br /&gt;
BitFail=0 (limit=5) &lt;br /&gt;
BitFailRate=0.0000 (limit=0.1) &lt;br /&gt;
-&amp;gt; Retrain&lt;br /&gt;
2026.01.01 18:27:19.280 1: SolCast DEBUG&amp;gt; Retry attempt 1 with Seed=16816002&lt;br /&gt;
2026.01.01 18:27:19.287 1: SolCast DEBUG&amp;gt; AI FANN Training started with Params:&lt;br /&gt;
num input datasets=7314, &lt;br /&gt;
training algo=FANN_TRAIN_INCREMENTAL, &lt;br /&gt;
output AF=LINEAR, &lt;br /&gt;
hidden AF=SIGMOID, &lt;br /&gt;
hidden Neurons=80,40,20, &lt;br /&gt;
hidden steepness=0.9, &lt;br /&gt;
Epoches=15000, &lt;br /&gt;
mse_error=0.001, &lt;br /&gt;
learning rate=0.00500, &lt;br /&gt;
learning momentum=0.7, &lt;br /&gt;
Data sharing=split after shuffle of training data and use AI internal shuffle (Train=5851, Test=1462), &lt;br /&gt;
Data shuffle=2 (period=10)&lt;br /&gt;
2026.01.01 18:27:19.448 1: SolCast DEBUG&amp;gt; Epoche 1: Train MSE=0.002204, Val MSE=0.002840, Val MAE=0.031967, Val MedAE=0.027950, Bit_Fail=2 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:27:27.760 1: SolCast DEBUG&amp;gt; Epoche 55: Train MSE=0.001883, Val MSE=0.002825, Val MAE=0.030076, Val MedAE=0.017712, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:27.909 1: SolCast DEBUG&amp;gt; Epoche 56: Train MSE=0.001848, Val MSE=0.002787, Val MAE=0.029877, Val MedAE=0.017254, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:28.093 1: SolCast DEBUG&amp;gt; Epoche 57: Train MSE=0.001806, Val MSE=0.002742, Val MAE=0.029648, Val MedAE=0.016877, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:28.250 1: SolCast DEBUG&amp;gt; Epoche 58: Train MSE=0.001759, Val MSE=0.002690, Val MAE=0.029392, Val MedAE=0.016720, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:28.410 1: SolCast DEBUG&amp;gt; Epoche 59: Train MSE=0.001704, Val MSE=0.002632, Val MAE=0.029109, Val MedAE=0.016686, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:34.691 1: SolCast DEBUG&amp;gt; Epoche 100: Train MSE=0.001704, Val MSE=0.001681, Val MAE=0.026853, Val MedAE=0.019229, Bit_Fail=1&lt;br /&gt;
2026.01.01 18:27:39.980 1: SolCast DEBUG&amp;gt; Epoche 133: Train MSE=0.000733, Val MSE=0.001267, Val MAE=0.023793, Val MedAE=0.017436, Bit_Fail=1 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:27:40.226 1: SolCast DEBUG&amp;gt; Epoche 134: Train MSE=0.000722, Val MSE=0.001247, Val MAE=0.023624, Val MedAE=0.017294, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:40.470 1: SolCast DEBUG&amp;gt; Epoche 135: Train MSE=0.000710, Val MSE=0.001225, Val MAE=0.023450, Val MedAE=0.017111, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:40.655 1: SolCast DEBUG&amp;gt; Epoche 136: Train MSE=0.000698, Val MSE=0.001204, Val MAE=0.023271, Val MedAE=0.017081, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:40.821 1: SolCast DEBUG&amp;gt; Epoche 137: Train MSE=0.000686, Val MSE=0.001182, Val MAE=0.023085, Val MedAE=0.017060, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:40.979 1: SolCast DEBUG&amp;gt; Epoche 138: Train MSE=0.000674, Val MSE=0.001160, Val MAE=0.022895, Val MedAE=0.016883, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:41.140 1: SolCast DEBUG&amp;gt; Epoche 139: Train MSE=0.000661, Val MSE=0.001138, Val MAE=0.022701, Val MedAE=0.016711, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:41.929 1: SolCast DEBUG&amp;gt; Epoche 144: Train MSE=0.000598, Val MSE=0.000999, Val MAE=0.021734, Val MedAE=0.016540, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:42.090 1: SolCast DEBUG&amp;gt; Epoche 145: Train MSE=0.000586, Val MSE=0.000978, Val MAE=0.021522, Val MedAE=0.016349, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:42.280 1: SolCast DEBUG&amp;gt; Epoche 146: Train MSE=0.000574, Val MSE=0.000958, Val MAE=0.021306, Val MedAE=0.016107, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:42.459 1: SolCast DEBUG&amp;gt; Epoche 147: Train MSE=0.000562, Val MSE=0.000937, Val MAE=0.021088, Val MedAE=0.015901, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:42.613 1: SolCast DEBUG&amp;gt; Epoche 148: Train MSE=0.000550, Val MSE=0.000918, Val MAE=0.020870, Val MedAE=0.015669, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:42.760 1: SolCast DEBUG&amp;gt; Epoche 149: Train MSE=0.000539, Val MSE=0.000898, Val MAE=0.020654, Val MedAE=0.015555, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:43.090 1: SolCast DEBUG&amp;gt; Epoche 151: Train MSE=0.000519, Val MSE=0.000853, Val MAE=0.020213, Val MedAE=0.015324, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:43.274 1: SolCast DEBUG&amp;gt; Epoche 152: Train MSE=0.000508, Val MSE=0.000834, Val MAE=0.019989, Val MedAE=0.015218, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:43.427 1: SolCast DEBUG&amp;gt; Epoche 153: Train MSE=0.000498, Val MSE=0.000815, Val MAE=0.019775, Val MedAE=0.015098, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:43.588 1: SolCast DEBUG&amp;gt; Epoche 154: Train MSE=0.000489, Val MSE=0.000798, Val MAE=0.019572, Val MedAE=0.015089, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:43.765 1: SolCast DEBUG&amp;gt; Epoche 155: Train MSE=0.000480, Val MSE=0.000781, Val MAE=0.019377, Val MedAE=0.014943, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:43.922 1: SolCast DEBUG&amp;gt; Epoche 156: Train MSE=0.000471, Val MSE=0.000765, Val MAE=0.019192, Val MedAE=0.014814, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:44.099 1: SolCast DEBUG&amp;gt; Epoche 157: Train MSE=0.000463, Val MSE=0.000750, Val MAE=0.019017, Val MedAE=0.014635, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:44.451 1: SolCast DEBUG&amp;gt; Epoche 159: Train MSE=0.000448, Val MSE=0.000722, Val MAE=0.018698, Val MedAE=0.014553, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:45.216 1: SolCast DEBUG&amp;gt; Epoche 164: Train MSE=0.000417, Val MSE=0.000649, Val MAE=0.018205, Val MedAE=0.014516, Bit_Fail=0 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:27:45.399 1: SolCast DEBUG&amp;gt; Epoche 165: Train MSE=0.000412, Val MSE=0.000640, Val MAE=0.018099, Val MedAE=0.014421, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:45.558 1: SolCast DEBUG&amp;gt; Epoche 166: Train MSE=0.000407, Val MSE=0.000632, Val MAE=0.017999, Val MedAE=0.014286, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:45.726 1: SolCast DEBUG&amp;gt; Epoche 167: Train MSE=0.000402, Val MSE=0.000624, Val MAE=0.017906, Val MedAE=0.014177, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:45.885 1: SolCast DEBUG&amp;gt; Epoche 168: Train MSE=0.000398, Val MSE=0.000617, Val MAE=0.017820, Val MedAE=0.014094, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:46.051 1: SolCast DEBUG&amp;gt; Epoche 169: Train MSE=0.000394, Val MSE=0.000610, Val MAE=0.017740, Val MedAE=0.014051, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:50.636 1: SolCast DEBUG&amp;gt; Epoche 200: Train MSE=0.000394, Val MSE=0.000539, Val MAE=0.016987, Val MedAE=0.013961, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:27:50.644 1: SolCast DEBUG&amp;gt; Epoche 200: Train MSE=0.000340, Val MSE=0.000539, Val MAE=0.016987, Val MedAE=0.013961, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:51.095 1: SolCast DEBUG&amp;gt; Epoche 203: Train MSE=0.000338, Val MSE=0.000538, Val MAE=0.016940, Val MedAE=0.013888, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:27:55.790 1: SolCast DEBUG&amp;gt; Epoche 233: Train MSE=0.000321, Val MSE=0.000535, Val MAE=0.016852, Val MedAE=0.013875, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:03.726 1: SolCast DEBUG&amp;gt; Epoche 281: Train MSE=0.000308, Val MSE=0.000524, Val MAE=0.016435, Val MedAE=0.013831, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:04.363 1: SolCast DEBUG&amp;gt; Epoche 285: Train MSE=0.000307, Val MSE=0.000523, Val MAE=0.016426, Val MedAE=0.013765, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:06.794 1: SolCast DEBUG&amp;gt; Epoche 300: Train MSE=0.000307, Val MSE=0.000550, Val MAE=0.017907, Val MedAE=0.015240, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:28:08.309 1: SolCast DEBUG&amp;gt; Epoche 310: Train MSE=0.000306, Val MSE=0.000520, Val MAE=0.016274, Val MedAE=0.013632, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:08.614 1: SolCast DEBUG&amp;gt; Epoche 312: Train MSE=0.000305, Val MSE=0.000519, Val MAE=0.016257, Val MedAE=0.013585, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:09.360 1: SolCast DEBUG&amp;gt; Epoche 317: Train MSE=0.000304, Val MSE=0.000518, Val MAE=0.016235, Val MedAE=0.013539, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:18.741 1: SolCast DEBUG&amp;gt; Epoche 370: Train MSE=0.000293, Val MSE=0.000514, Val MAE=0.016166, Val MedAE=0.013205, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:23.398 1: SolCast DEBUG&amp;gt; Epoche 400: Train MSE=0.000293, Val MSE=0.000498, Val MAE=0.016166, Val MedAE=0.013530, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:28:27.156 1: SolCast DEBUG&amp;gt; Epoche 420: Train MSE=0.000286, Val MSE=0.000497, Val MAE=0.015836, Val MedAE=0.012658, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:27.956 1: SolCast DEBUG&amp;gt; Epoche 424: Train MSE=0.000286, Val MSE=0.000496, Val MAE=0.015803, Val MedAE=0.012630, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:28.927 1: SolCast DEBUG&amp;gt; Epoche 429: Train MSE=0.000285, Val MSE=0.000495, Val MAE=0.015779, Val MedAE=0.012568, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:37.533 1: SolCast DEBUG&amp;gt; Epoche 470: Train MSE=0.000278, Val MSE=0.000490, Val MAE=0.015754, Val MedAE=0.012467, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:44.668 1: SolCast DEBUG&amp;gt; Epoche 500: Train MSE=0.000278, Val MSE=0.000512, Val MAE=0.015775, Val MedAE=0.011966, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:28:49.391 1: SolCast DEBUG&amp;gt; Epoche 520: Train MSE=0.000270, Val MSE=0.000477, Val MAE=0.015651, Val MedAE=0.012339, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:28:53.585 1: SolCast DEBUG&amp;gt; Epoche 539: Train MSE=0.000270, Val MSE=0.000475, Val MAE=0.015648, Val MedAE=0.012191, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:29:05.842 1: SolCast DEBUG&amp;gt; Epoche 590: Train MSE=0.000265, Val MSE=0.000474, Val MAE=0.015526, Val MedAE=0.012056, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:29:08.065 1: SolCast DEBUG&amp;gt; Epoche 600: Train MSE=0.000265, Val MSE=0.000468, Val MAE=0.015894, Val MedAE=0.012751, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:29:28.474 1: SolCast DEBUG&amp;gt; Epoche 690: Train MSE=0.000256, Val MSE=0.000470, Val MAE=0.015276, Val MedAE=0.011856, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:29:30.383 1: SolCast DEBUG&amp;gt; Epoche 699: Train MSE=0.000255, Val MSE=0.000467, Val MAE=0.015250, Val MedAE=0.011836, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:29:30.639 1: SolCast DEBUG&amp;gt; Epoche 700: Train MSE=0.000255, Val MSE=0.000478, Val MAE=0.016548, Val MedAE=0.013898, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:29:52.830 1: SolCast DEBUG&amp;gt; Epoche 800: Train MSE=0.000255, Val MSE=0.000465, Val MAE=0.016306, Val MedAE=0.013391, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:30:04.934 1: SolCast DEBUG&amp;gt; Epoche 850: Train MSE=0.000244, Val MSE=0.000461, Val MAE=0.015129, Val MedAE=0.011815, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:30:17.777 1: SolCast DEBUG&amp;gt; Epoche 900: Train MSE=0.000244, Val MSE=0.000448, Val MAE=0.015585, Val MedAE=0.012575, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:30:40.850 1: SolCast DEBUG&amp;gt; Epoche 1000: Train MSE=0.000244, Val MSE=0.000450, Val MAE=0.015295, Val MedAE=0.012324, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:30:56.457 1: SolCast DEBUG&amp;gt; Epoche 1100: Train MSE=0.000244, Val MSE=0.000443, Val MAE=0.015695, Val MedAE=0.012932, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:31:07.100 1: SolCast DEBUG&amp;gt; Epoche 1160: Train MSE=0.000229, Val MSE=0.000432, Val MAE=0.014957, Val MedAE=0.011802, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:31:13.278 1: SolCast DEBUG&amp;gt; Epoche 1200: Train MSE=0.000229, Val MSE=0.000439, Val MAE=0.015822, Val MedAE=0.012868, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:31:29.055 1: SolCast DEBUG&amp;gt; Epoche 1300: Train MSE=0.000229, Val MSE=0.000435, Val MAE=0.015613, Val MedAE=0.012747, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:31:43.689 1: SolCast DEBUG&amp;gt; Epoche 1390: Train MSE=0.000219, Val MSE=0.000426, Val MAE=0.014936, Val MedAE=0.011470, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:31:45.625 1: SolCast DEBUG&amp;gt; Epoche 1400: Train MSE=0.000219, Val MSE=0.000414, Val MAE=0.014586, Val MedAE=0.011035, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:31:45.635 1: SolCast DEBUG&amp;gt; Epoche 1400: Train MSE=0.000218, Val MSE=0.000414, Val MAE=0.014586, Val MedAE=0.011035, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:32:02.161 1: SolCast DEBUG&amp;gt; Epoche 1500: Train MSE=0.000218, Val MSE=0.000449, Val MAE=0.016432, Val MedAE=0.013464, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:32:18.086 1: SolCast DEBUG&amp;gt; Epoche 1600: Train MSE=0.000218, Val MSE=0.000403, Val MAE=0.014934, Val MedAE=0.011695, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:32:32.114 1: SolCast DEBUG&amp;gt; Epoche 1690: Train MSE=0.000209, Val MSE=0.000404, Val MAE=0.014320, Val MedAE=0.010320, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:32:33.832 1: SolCast DEBUG&amp;gt; Epoche 1700: Train MSE=0.000209, Val MSE=0.000428, Val MAE=0.016037, Val MedAE=0.012994, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:32:49.865 1: SolCast DEBUG&amp;gt; Epoche 1800: Train MSE=0.000209, Val MSE=0.000410, Val MAE=0.015653, Val MedAE=0.012577, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:33:02.182 1: SolCast DEBUG&amp;gt; Epoche 1870: Train MSE=0.000205, Val MSE=0.000383, Val MAE=0.014067, Val MedAE=0.010133, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:33:06.890 1: SolCast DEBUG&amp;gt; Epoche 1900: Train MSE=0.000205, Val MSE=0.000376, Val MAE=0.014446, Val MedAE=0.011115, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:33:22.858 1: SolCast DEBUG&amp;gt; Epoche 2000: Train MSE=0.000205, Val MSE=0.000368, Val MAE=0.014258, Val MedAE=0.010752, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:33:38.578 1: SolCast DEBUG&amp;gt; Epoche 2100: Train MSE=0.000205, Val MSE=0.000440, Val MAE=0.016680, Val MedAE=0.014515, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:33:41.611 1: SolCast DEBUG&amp;gt; Epoche 2120: Train MSE=0.000198, Val MSE=0.000367, Val MAE=0.013801, Val MedAE=0.009661, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:33:54.354 1: SolCast DEBUG&amp;gt; Epoche 2200: Train MSE=0.000198, Val MSE=0.000417, Val MAE=0.016140, Val MedAE=0.013713, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:34:11.686 1: SolCast DEBUG&amp;gt; Epoche 2300: Train MSE=0.000198, Val MSE=0.000362, Val MAE=0.014348, Val MedAE=0.010921, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:34:18.148 1: SolCast DEBUG&amp;gt; Epoche 2340: Train MSE=0.000195, Val MSE=0.000356, Val MAE=0.013592, Val MedAE=0.009300, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:34:27.489 1: SolCast DEBUG&amp;gt; Epoche 2400: Train MSE=0.000195, Val MSE=0.000355, Val MAE=0.014051, Val MedAE=0.010411, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:34:43.305 1: SolCast DEBUG&amp;gt; Epoche 2500: Train MSE=0.000195, Val MSE=0.000349, Val MAE=0.013577, Val MedAE=0.009666, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:34:58.973 1: SolCast DEBUG&amp;gt; Epoche 2600: Train MSE=0.000195, Val MSE=0.000377, Val MAE=0.015170, Val MedAE=0.012456, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:35:15.415 1: SolCast DEBUG&amp;gt; Epoche 2700: Train MSE=0.000195, Val MSE=0.000340, Val MAE=0.013970, Val MedAE=0.010876, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:35:32.017 1: SolCast DEBUG&amp;gt; Epoche 2800: Train MSE=0.000195, Val MSE=0.000382, Val MAE=0.015341, Val MedAE=0.012854, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:35:47.827 1: SolCast DEBUG&amp;gt; Epoche 2900: Train MSE=0.000195, Val MSE=0.000328, Val MAE=0.013411, Val MedAE=0.009790, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:35:52.375 1: SolCast DEBUG&amp;gt; Epoche 2931: Train MSE=0.000186, Val MSE=0.000331, Val MAE=0.013276, Val MedAE=0.009297, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:36:04.885 1: SolCast DEBUG&amp;gt; Epoche 3000: Train MSE=0.000186, Val MSE=0.000333, Val MAE=0.013785, Val MedAE=0.010478, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:36:20.725 1: SolCast DEBUG&amp;gt; Epoche 3100: Train MSE=0.000186, Val MSE=0.000329, Val MAE=0.013228, Val MedAE=0.009287, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:36:20.735 1: SolCast DEBUG&amp;gt; Epoche 3100: Train MSE=0.000184, Val MSE=0.000329, Val MAE=0.013228, Val MedAE=0.009287, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:36:34.489 1: SolCast DEBUG&amp;gt; Epoche 3180: Train MSE=0.000182, Val MSE=0.000327, Val MAE=0.013125, Val MedAE=0.008939, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:36:38.029 1: SolCast DEBUG&amp;gt; Epoche 3200: Train MSE=0.000182, Val MSE=0.000320, Val MAE=0.013228, Val MedAE=0.009632, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:36:45.842 1: SolCast DEBUG&amp;gt; Epoche 3250: Train MSE=0.000183, Val MSE=0.000323, Val MAE=0.013096, Val MedAE=0.008886, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:36:53.303 1: SolCast DEBUG&amp;gt; Epoche 3300: Train MSE=0.000183, Val MSE=0.000320, Val MAE=0.013318, Val MedAE=0.009760, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:37:09.545 1: SolCast DEBUG&amp;gt; Epoche 3400: Train MSE=0.000183, Val MSE=0.000327, Val MAE=0.013922, Val MedAE=0.011272, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:37:24.189 1: SolCast DEBUG&amp;gt; Epoche 3490: Train MSE=0.000180, Val MSE=0.000319, Val MAE=0.013041, Val MedAE=0.008820, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:37:25.723 1: SolCast DEBUG&amp;gt; Epoche 3500: Train MSE=0.000180, Val MSE=0.000323, Val MAE=0.013588, Val MedAE=0.010386, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:37:47.590 1: SolCast DEBUG&amp;gt; Epoche 3600: Train MSE=0.000180, Val MSE=0.000323, Val MAE=0.013730, Val MedAE=0.010947, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:37:53.258 1: SolCast DEBUG&amp;gt; Epoche 3630: Train MSE=0.000178, Val MSE=0.000318, Val MAE=0.012948, Val MedAE=0.008677, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:38:09.034 1: SolCast DEBUG&amp;gt; Epoche 3700: Train MSE=0.000178, Val MSE=0.000312, Val MAE=0.013378, Val MedAE=0.010497, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:38:30.192 1: SolCast DEBUG&amp;gt; Epoche 3800: Train MSE=0.000178, Val MSE=0.000312, Val MAE=0.013379, Val MedAE=0.010674, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:38:52.224 1: SolCast DEBUG&amp;gt; Epoche 3900: Train MSE=0.000178, Val MSE=0.000318, Val MAE=0.012933, Val MedAE=0.008471, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:39:13.603 1: SolCast DEBUG&amp;gt; Epoche 4000: Train MSE=0.000178, Val MSE=0.000306, Val MAE=0.013228, Val MedAE=0.010395, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:39:34.047 1: SolCast DEBUG&amp;gt; Epoche 4100: Train MSE=0.000178, Val MSE=0.000318, Val MAE=0.013793, Val MedAE=0.011333, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:39:54.812 1: SolCast DEBUG&amp;gt; Epoche 4200: Train MSE=0.000178, Val MSE=0.000309, Val MAE=0.013388, Val MedAE=0.010831, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:40:02.202 1: SolCast DEBUG&amp;gt; Epoche 4230: Train MSE=0.000175, Val MSE=0.000309, Val MAE=0.012845, Val MedAE=0.008584, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:40:16.021 1: SolCast DEBUG&amp;gt; Epoche 4300: Train MSE=0.000175, Val MSE=0.000303, Val MAE=0.013012, Val MedAE=0.009822, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:40:34.355 1: SolCast DEBUG&amp;gt; Epoche 4400: Train MSE=0.000175, Val MSE=0.000310, Val MAE=0.012884, Val MedAE=0.008766, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:40:57.218 1: SolCast DEBUG&amp;gt; Epoche 4500: Train MSE=0.000175, Val MSE=0.000302, Val MAE=0.013128, Val MedAE=0.010345, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:41:22.220 1: SolCast DEBUG&amp;gt; Epoche 4600: Train MSE=0.000175, Val MSE=0.000302, Val MAE=0.013191, Val MedAE=0.010385, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:41:43.986 1: SolCast DEBUG&amp;gt; Epoche 4700: Train MSE=0.000175, Val MSE=0.000301, Val MAE=0.013269, Val MedAE=0.010709, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:42:05.591 1: SolCast DEBUG&amp;gt; Epoche 4800: Train MSE=0.000175, Val MSE=0.000327, Val MAE=0.012984, Val MedAE=0.008358, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:42:28.817 1: SolCast DEBUG&amp;gt; Epoche 4900: Train MSE=0.000175, Val MSE=0.000300, Val MAE=0.013196, Val MedAE=0.010534, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:42:51.092 1: SolCast DEBUG&amp;gt; Epoche 5000: Train MSE=0.000175, Val MSE=0.000298, Val MAE=0.013025, Val MedAE=0.010142, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:43:13.597 1: SolCast DEBUG&amp;gt; Epoche 5100: Train MSE=0.000175, Val MSE=0.000296, Val MAE=0.012895, Val MedAE=0.009981, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:43:36.900 1: SolCast DEBUG&amp;gt; Epoche 5200: Train MSE=0.000175, Val MSE=0.000298, Val MAE=0.012955, Val MedAE=0.009983, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:43:58.243 1: SolCast DEBUG&amp;gt; Epoche 5300: Train MSE=0.000175, Val MSE=0.000305, Val MAE=0.013474, Val MedAE=0.010999, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:44:20.399 1: SolCast DEBUG&amp;gt; Epoche 5400: Train MSE=0.000175, Val MSE=0.000296, Val MAE=0.012941, Val MedAE=0.009892, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:44:37.326 1: SolCast DEBUG&amp;gt; Epoche 5500: Train MSE=0.000175, Val MSE=0.000301, Val MAE=0.013345, Val MedAE=0.010900, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:44:53.049 1: SolCast DEBUG&amp;gt; Epoche 5600: Train MSE=0.000175, Val MSE=0.000297, Val MAE=0.012997, Val MedAE=0.010176, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:45:10.274 1: SolCast DEBUG&amp;gt; Epoche 5700: Train MSE=0.000175, Val MSE=0.000303, Val MAE=0.013484, Val MedAE=0.011050, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:45:27.329 1: SolCast DEBUG&amp;gt; Epoche 5800: Train MSE=0.000175, Val MSE=0.000300, Val MAE=0.013419, Val MedAE=0.011095, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:45:42.673 1: SolCast DEBUG&amp;gt; Epoche 5900: Train MSE=0.000175, Val MSE=0.000295, Val MAE=0.013058, Val MedAE=0.010464, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:45:59.007 1: SolCast DEBUG&amp;gt; Epoche 6000: Train MSE=0.000175, Val MSE=0.000299, Val MAE=0.012793, Val MedAE=0.009330, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:46:14.775 1: SolCast DEBUG&amp;gt; Epoche 6100: Train MSE=0.000175, Val MSE=0.000294, Val MAE=0.013040, Val MedAE=0.010396, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:46:29.912 1: SolCast DEBUG&amp;gt; Epoche 6200: Train MSE=0.000175, Val MSE=0.000305, Val MAE=0.013656, Val MedAE=0.011383, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:46:34.543 1: SolCast DEBUG&amp;gt; Early stopping bei Epoche 6230 (no improvement since 2000 epochs)&lt;br /&gt;
2026.01.01 18:46:34.546 1: === Snapshot-Statistik ===&lt;br /&gt;
2026.01.01 18:46:34.547 1: Metric-Improvement Snapshots: 63 (letzte Epoche: 4230)&lt;br /&gt;
2026.01.01 18:46:34.549 1: Bit-Improvement Snapshots:    3 (letzte Epoche: 164)&lt;br /&gt;
2026.01.01 18:46:34.552 1: Bit-Tradeoff Snapshots:       0 (letzte Epoche: 0)&lt;br /&gt;
2026.01.01 18:46:34.559 1: SolCast DEBUG&amp;gt; Best Snapshot reloaded from Epoche 4230: Train MSE=0.000175, Val MSE=0.000309, Val MAE=0.012845, Val MedAE=0.008584, Bit_Fail=0,&lt;br /&gt;
2026.01.01 18:46:34.561 1: SolCast DEBUG&amp;gt; Run Validation Test with 20% of Input data ...&lt;br /&gt;
2026.01.01 18:46:34.602 1: SolCast DEBUG&amp;gt; Validation finished - Best Training MSE=0.000175, Validation MSE=0.000309, Validation Bit_Fail=0&lt;br /&gt;
2026.01.01 18:46:34.605 1: SolCast DEBUG&amp;gt; Retrain check -&amp;gt; &lt;br /&gt;
-- In Normalization Space: -- &lt;br /&gt;
Train MSE=0.000175 &lt;br /&gt;
Val MSE=0.000309 &lt;br /&gt;
Val Mean=0.0003042089 &lt;br /&gt;
VAL/TRAIN MSE Ratio=1.763249 (limit=2.5) &lt;br /&gt;
Diff=0.000134 (limit=0.005) &lt;br /&gt;
ValStd=0.0000076839 (limit=7.60522365479913e-05) &lt;br /&gt;
-- At Original Scale: -- &lt;br /&gt;
MAE=211.576764064665 &lt;br /&gt;
RMSE/MAE=1.3694 (limit=1.5) &lt;br /&gt;
Slope=0.935893 (limit=0.7 .. 1.3) &lt;br /&gt;
Bias=4.36 (limit=+-105.788382032332) &lt;br /&gt;
R2=0.890528595577006 &lt;br /&gt;
P95=585.8856 (limit=846.307056258658) &lt;br /&gt;
P99=968.7970 (limit=1692.61411251732) &lt;br /&gt;
-- Robustness Indicators: -- &lt;br /&gt;
RMSE relative=62 (limit=20) &lt;br /&gt;
BitFail=0 (limit=5) &lt;br /&gt;
BitFailRate=0.0000 (limit=0.1) &lt;br /&gt;
-&amp;gt; Retrain&lt;br /&gt;
2026.01.01 18:46:34.613 1: SolCast DEBUG&amp;gt; Retry attempt 2 with Seed=16325084&lt;br /&gt;
2026.01.01 18:46:34.619 1: SolCast DEBUG&amp;gt; AI FANN Training started with Params:&lt;br /&gt;
num input datasets=7314, &lt;br /&gt;
training algo=FANN_TRAIN_INCREMENTAL, &lt;br /&gt;
output AF=LINEAR, &lt;br /&gt;
hidden AF=SIGMOID, &lt;br /&gt;
hidden Neurons=80,40,20, &lt;br /&gt;
hidden steepness=0.9, &lt;br /&gt;
Epoches=15000, &lt;br /&gt;
mse_error=0.001, &lt;br /&gt;
learning rate=0.00500, &lt;br /&gt;
learning momentum=0.7, &lt;br /&gt;
Data sharing=split after shuffle of training data and use AI internal shuffle (Train=5851, Test=1462), &lt;br /&gt;
Data shuffle=2 (period=10)&lt;br /&gt;
2026.01.01 18:46:34.804 1: SolCast DEBUG&amp;gt; Epoche 1: Train MSE=0.002232, Val MSE=0.002836, Val MAE=0.031928, Val MedAE=0.027901, Bit_Fail=2 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:46:35.250 1: SolCast DEBUG&amp;gt; Epoche 4: Train MSE=0.002191, Val MSE=0.002835, Val MAE=0.031923, Val MedAE=0.027895, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:35.703 1: SolCast DEBUG&amp;gt; Epoche 7: Train MSE=0.002187, Val MSE=0.002834, Val MAE=0.031919, Val MedAE=0.027892, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:42.846 1: SolCast DEBUG&amp;gt; Epoche 54: Train MSE=0.002012, Val MSE=0.002830, Val MAE=0.030056, Val MedAE=0.024398, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:42.997 1: SolCast DEBUG&amp;gt; Epoche 55: Train MSE=0.001999, Val MSE=0.002816, Val MAE=0.029980, Val MedAE=0.024096, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:43.151 1: SolCast DEBUG&amp;gt; Epoche 56: Train MSE=0.001984, Val MSE=0.002799, Val MAE=0.029892, Val MedAE=0.023790, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:43.302 1: SolCast DEBUG&amp;gt; Epoche 57: Train MSE=0.001966, Val MSE=0.002780, Val MAE=0.029791, Val MedAE=0.023427, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:43.459 1: SolCast DEBUG&amp;gt; Epoche 58: Train MSE=0.001945, Val MSE=0.002756, Val MAE=0.029676, Val MedAE=0.022958, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:43.623 1: SolCast DEBUG&amp;gt; Epoche 59: Train MSE=0.001920, Val MSE=0.002728, Val MAE=0.029540, Val MedAE=0.022374, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:44.667 1: SolCast DEBUG&amp;gt; Epoche 65: Train MSE=0.001639, Val MSE=0.002678, Val MAE=0.029156, Val MedAE=0.016122, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:50.165 1: SolCast DEBUG&amp;gt; Epoche 100: Train MSE=0.001639, Val MSE=0.001617, Val MAE=0.027389, Val MedAE=0.021329, Bit_Fail=1&lt;br /&gt;
2026.01.01 18:46:57.117 1: SolCast DEBUG&amp;gt; Epoche 140: Train MSE=0.000582, Val MSE=0.000982, Val MAE=0.021762, Val MedAE=0.016481, Bit_Fail=1 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:46:57.374 1: SolCast DEBUG&amp;gt; Epoche 141: Train MSE=0.000571, Val MSE=0.000963, Val MAE=0.021553, Val MedAE=0.016314, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:57.625 1: SolCast DEBUG&amp;gt; Epoche 142: Train MSE=0.000559, Val MSE=0.000944, Val MAE=0.021340, Val MedAE=0.015998, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:57.814 1: SolCast DEBUG&amp;gt; Epoche 143: Train MSE=0.000548, Val MSE=0.000925, Val MAE=0.021128, Val MedAE=0.015847, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:58.048 1: SolCast DEBUG&amp;gt; Epoche 144: Train MSE=0.000537, Val MSE=0.000906, Val MAE=0.020921, Val MedAE=0.015525, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:58.217 1: SolCast DEBUG&amp;gt; Epoche 145: Train MSE=0.000526, Val MSE=0.000888, Val MAE=0.020716, Val MedAE=0.015427, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:58.387 1: SolCast DEBUG&amp;gt; Epoche 146: Train MSE=0.000516, Val MSE=0.000871, Val MAE=0.020515, Val MedAE=0.015357, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:58.797 1: SolCast DEBUG&amp;gt; Epoche 148: Train MSE=0.000497, Val MSE=0.000838, Val MAE=0.020132, Val MedAE=0.015318, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:58.986 1: SolCast DEBUG&amp;gt; Epoche 149: Train MSE=0.000488, Val MSE=0.000822, Val MAE=0.019953, Val MedAE=0.015200, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:59.141 1: SolCast DEBUG&amp;gt; Epoche 150: Train MSE=0.000482, Val MSE=0.000817, Val MAE=0.019792, Val MedAE=0.015107, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:59.316 1: SolCast DEBUG&amp;gt; Epoche 151: Train MSE=0.000474, Val MSE=0.000802, Val MAE=0.019630, Val MedAE=0.014972, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:59.471 1: SolCast DEBUG&amp;gt; Epoche 152: Train MSE=0.000466, Val MSE=0.000788, Val MAE=0.019477, Val MedAE=0.014905, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:59.637 1: SolCast DEBUG&amp;gt; Epoche 153: Train MSE=0.000459, Val MSE=0.000775, Val MAE=0.019332, Val MedAE=0.014836, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:59.795 1: SolCast DEBUG&amp;gt; Epoche 154: Train MSE=0.000452, Val MSE=0.000763, Val MAE=0.019196, Val MedAE=0.014833, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:46:59.953 1: SolCast DEBUG&amp;gt; Epoche 155: Train MSE=0.000446, Val MSE=0.000751, Val MAE=0.019068, Val MedAE=0.014766, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:00.128 1: SolCast DEBUG&amp;gt; Epoche 156: Train MSE=0.000440, Val MSE=0.000740, Val MAE=0.018949, Val MedAE=0.014751, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:00.423 1: SolCast DEBUG&amp;gt; Epoche 157: Train MSE=0.000434, Val MSE=0.000729, Val MAE=0.018837, Val MedAE=0.014571, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:00.580 1: SolCast DEBUG&amp;gt; Epoche 158: Train MSE=0.000429, Val MSE=0.000719, Val MAE=0.018732, Val MedAE=0.014399, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:00.738 1: SolCast DEBUG&amp;gt; Epoche 159: Train MSE=0.000423, Val MSE=0.000710, Val MAE=0.018632, Val MedAE=0.014296, Bit_Fail=0 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 18:47:04.664 1: SolCast DEBUG&amp;gt; Epoche 185: Train MSE=0.000352, Val MSE=0.000570, Val MAE=0.017726, Val MedAE=0.014241, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:04.823 1: SolCast DEBUG&amp;gt; Epoche 186: Train MSE=0.000351, Val MSE=0.000568, Val MAE=0.017700, Val MedAE=0.014157, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:04.998 1: SolCast DEBUG&amp;gt; Epoche 187: Train MSE=0.000350, Val MSE=0.000567, Val MAE=0.017676, Val MedAE=0.014128, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:05.330 1: SolCast DEBUG&amp;gt; Epoche 189: Train MSE=0.000347, Val MSE=0.000565, Val MAE=0.017630, Val MedAE=0.014111, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:07.326 1: SolCast DEBUG&amp;gt; Epoche 200: Train MSE=0.000347, Val MSE=0.000560, Val MAE=0.017645, Val MedAE=0.014294, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:47:08.430 1: SolCast DEBUG&amp;gt; Epoche 207: Train MSE=0.000336, Val MSE=0.000557, Val MAE=0.017581, Val MedAE=0.014098, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:08.925 1: SolCast DEBUG&amp;gt; Epoche 210: Train MSE=0.000332, Val MSE=0.000551, Val MAE=0.017149, Val MedAE=0.014015, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:09.251 1: SolCast DEBUG&amp;gt; Epoche 212: Train MSE=0.000331, Val MSE=0.000549, Val MAE=0.017106, Val MedAE=0.014013, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:09.543 1: SolCast DEBUG&amp;gt; Epoche 214: Train MSE=0.000330, Val MSE=0.000548, Val MAE=0.017079, Val MedAE=0.014009, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:19.704 1: SolCast DEBUG&amp;gt; Epoche 280: Train MSE=0.000312, Val MSE=0.000539, Val MAE=0.016444, Val MedAE=0.013594, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:22.914 1: SolCast DEBUG&amp;gt; Epoche 300: Train MSE=0.000312, Val MSE=0.000547, Val MAE=0.017776, Val MedAE=0.014873, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:47:36.920 1: SolCast DEBUG&amp;gt; Epoche 390: Train MSE=0.000299, Val MSE=0.000534, Val MAE=0.016256, Val MedAE=0.013227, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:37.075 1: SolCast DEBUG&amp;gt; Epoche 391: Train MSE=0.000299, Val MSE=0.000533, Val MAE=0.016248, Val MedAE=0.013207, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:37.692 1: SolCast DEBUG&amp;gt; Epoche 395: Train MSE=0.000298, Val MSE=0.000532, Val MAE=0.016231, Val MedAE=0.013184, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:38.408 1: SolCast DEBUG&amp;gt; Epoche 400: Train MSE=0.000298, Val MSE=0.000533, Val MAE=0.016139, Val MedAE=0.013128, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:47:43.011 1: SolCast DEBUG&amp;gt; Epoche 430: Train MSE=0.000294, Val MSE=0.000524, Val MAE=0.016053, Val MedAE=0.013160, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:47:53.755 1: SolCast DEBUG&amp;gt; Epoche 500: Train MSE=0.000294, Val MSE=0.000533, Val MAE=0.017601, Val MedAE=0.015372, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:48:03.268 1: SolCast DEBUG&amp;gt; Epoche 560: Train MSE=0.000278, Val MSE=0.000499, Val MAE=0.015935, Val MedAE=0.013052, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:48:10.654 1: SolCast DEBUG&amp;gt; Epoche 600: Train MSE=0.000278, Val MSE=0.000497, Val MAE=0.016063, Val MedAE=0.013071, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:48:17.120 1: SolCast DEBUG&amp;gt; Epoche 640: Train MSE=0.000270, Val MSE=0.000494, Val MAE=0.015925, Val MedAE=0.012746, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:48:26.254 1: SolCast DEBUG&amp;gt; Epoche 700: Train MSE=0.000270, Val MSE=0.000494, Val MAE=0.016121, Val MedAE=0.012865, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:48:41.338 1: SolCast DEBUG&amp;gt; Epoche 800: Train MSE=0.000270, Val MSE=0.000496, Val MAE=0.016486, Val MedAE=0.013111, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:48:50.270 1: SolCast DEBUG&amp;gt; Epoche 860: Train MSE=0.000251, Val MSE=0.000491, Val MAE=0.015786, Val MedAE=0.012241, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:48:56.298 1: SolCast DEBUG&amp;gt; Epoche 900: Train MSE=0.000251, Val MSE=0.000539, Val MAE=0.017781, Val MedAE=0.014813, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:49:00.767 1: openMeteo - Open-Meteo API server response: start_SSL https://api.open-meteo.com:443 timed out&lt;br /&gt;
2026.01.01 18:49:11.666 1: SolCast DEBUG&amp;gt; Epoche 1000: Train MSE=0.000251, Val MSE=0.000487, Val MAE=0.015740, Val MedAE=0.012296, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:49:28.665 1: SolCast DEBUG&amp;gt; Epoche 1100: Train MSE=0.000251, Val MSE=0.000491, Val MAE=0.015728, Val MedAE=0.012462, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:49:39.207 1: SolCast DEBUG&amp;gt; Epoche 1168: Train MSE=0.000235, Val MSE=0.000479, Val MAE=0.015557, Val MedAE=0.012237, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:49:44.096 1: SolCast DEBUG&amp;gt; Epoche 1200: Train MSE=0.000235, Val MSE=0.000477, Val MAE=0.015613, Val MedAE=0.012266, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:49:59.330 1: SolCast DEBUG&amp;gt; Epoche 1300: Train MSE=0.000235, Val MSE=0.000469, Val MAE=0.015970, Val MedAE=0.012473, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:50:02.607 1: SolCast DEBUG&amp;gt; Epoche 1320: Train MSE=0.000230, Val MSE=0.000474, Val MAE=0.015490, Val MedAE=0.011887, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:50:15.063 1: SolCast DEBUG&amp;gt; Epoche 1400: Train MSE=0.000230, Val MSE=0.000469, Val MAE=0.016083, Val MedAE=0.012479, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:50:31.357 1: SolCast DEBUG&amp;gt; Epoche 1500: Train MSE=0.000230, Val MSE=0.000461, Val MAE=0.015731, Val MedAE=0.012435, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:50:43.405 1: SolCast DEBUG&amp;gt; Epoche 1570: Train MSE=0.000219, Val MSE=0.000452, Val MAE=0.015217, Val MedAE=0.011832, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:50:48.687 1: SolCast DEBUG&amp;gt; Epoche 1600: Train MSE=0.000219, Val MSE=0.000452, Val MAE=0.015676, Val MedAE=0.012380, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:51:00.785 1: SolCast DEBUG&amp;gt; Epoche 1680: Train MSE=0.000216, Val MSE=0.000447, Val MAE=0.015153, Val MedAE=0.011761, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:51:02.263 1: SolCast DEBUG&amp;gt; Epoche 1690: Train MSE=0.000215, Val MSE=0.000446, Val MAE=0.015014, Val MedAE=0.011740, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:51:03.808 1: SolCast DEBUG&amp;gt; Epoche 1700: Train MSE=0.000215, Val MSE=0.000444, Val MAE=0.015548, Val MedAE=0.012346, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:51:19.267 1: SolCast DEBUG&amp;gt; Epoche 1800: Train MSE=0.000215, Val MSE=0.000456, Val MAE=0.016255, Val MedAE=0.012272, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:51:28.478 1: SolCast DEBUG&amp;gt; Epoche 1860: Train MSE=0.000211, Val MSE=0.000430, Val MAE=0.014967, Val MedAE=0.011675, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:51:32.128 1: SolCast DEBUG&amp;gt; Epoche 1885: Train MSE=0.000210, Val MSE=0.000429, Val MAE=0.014936, Val MedAE=0.011634, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:51:34.991 1: SolCast DEBUG&amp;gt; Epoche 1900: Train MSE=0.000210, Val MSE=0.000431, Val MAE=0.015557, Val MedAE=0.012006, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:51:36.961 1: SolCast DEBUG&amp;gt; Epoche 1910: Train MSE=0.000209, Val MSE=0.000427, Val MAE=0.014927, Val MedAE=0.011633, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:51:44.135 1: SolCast DEBUG&amp;gt; Epoche 1950: Train MSE=0.000207, Val MSE=0.000425, Val MAE=0.014852, Val MedAE=0.011568, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:51:51.659 1: SolCast DEBUG&amp;gt; Epoche 2000: Train MSE=0.000207, Val MSE=0.000419, Val MAE=0.015028, Val MedAE=0.011705, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:52:07.280 1: SolCast DEBUG&amp;gt; Epoche 2100: Train MSE=0.000207, Val MSE=0.000419, Val MAE=0.015127, Val MedAE=0.011801, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:52:22.353 1: SolCast DEBUG&amp;gt; Epoche 2200: Train MSE=0.000207, Val MSE=0.000409, Val MAE=0.014933, Val MedAE=0.011578, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:52:25.518 1: SolCast DEBUG&amp;gt; Epoche 2220: Train MSE=0.000201, Val MSE=0.000401, Val MAE=0.014505, Val MedAE=0.011123, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:52:38.140 1: SolCast DEBUG&amp;gt; Epoche 2280: Train MSE=0.000200, Val MSE=0.000398, Val MAE=0.014426, Val MedAE=0.010998, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:52:40.466 1: SolCast DEBUG&amp;gt; Epoche 2290: Train MSE=0.000199, Val MSE=0.000397, Val MAE=0.014408, Val MedAE=0.010918, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:52:42.754 1: SolCast DEBUG&amp;gt; Epoche 2300: Train MSE=0.000199, Val MSE=0.000395, Val MAE=0.014771, Val MedAE=0.011372, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:53:06.020 1: SolCast DEBUG&amp;gt; Epoche 2400: Train MSE=0.000199, Val MSE=0.000386, Val MAE=0.014179, Val MedAE=0.010473, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:53:06.031 1: SolCast DEBUG&amp;gt; Epoche 2400: Train MSE=0.000196, Val MSE=0.000386, Val MAE=0.014179, Val MedAE=0.010473, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:53:27.648 1: SolCast DEBUG&amp;gt; Epoche 2500: Train MSE=0.000196, Val MSE=0.000394, Val MAE=0.015055, Val MedAE=0.011719, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:53:48.669 1: SolCast DEBUG&amp;gt; Epoche 2600: Train MSE=0.000196, Val MSE=0.000393, Val MAE=0.015223, Val MedAE=0.011833, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:54:04.615 1: SolCast DEBUG&amp;gt; Epoche 2670: Train MSE=0.000190, Val MSE=0.000363, Val MAE=0.014023, Val MedAE=0.010343, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:54:10.539 1: SolCast DEBUG&amp;gt; Epoche 2700: Train MSE=0.000190, Val MSE=0.000399, Val MAE=0.015520, Val MedAE=0.012166, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:54:22.630 1: SolCast DEBUG&amp;gt; Epoche 2762: Train MSE=0.000188, Val MSE=0.000359, Val MAE=0.014009, Val MedAE=0.010303, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:54:28.642 1: SolCast DEBUG&amp;gt; Epoche 2800: Train MSE=0.000188, Val MSE=0.000422, Val MAE=0.016216, Val MedAE=0.013541, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:54:36.250 1: SolCast DEBUG&amp;gt; Epoche 2850: Train MSE=0.000187, Val MSE=0.000356, Val MAE=0.013892, Val MedAE=0.010014, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:54:37.817 1: SolCast DEBUG&amp;gt; Epoche 2860: Train MSE=0.000186, Val MSE=0.000353, Val MAE=0.013781, Val MedAE=0.009785, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:54:43.894 1: SolCast DEBUG&amp;gt; Epoche 2900: Train MSE=0.000186, Val MSE=0.000373, Val MAE=0.014968, Val MedAE=0.011754, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:54:51.665 1: SolCast DEBUG&amp;gt; Epoche 2950: Train MSE=0.000184, Val MSE=0.000350, Val MAE=0.013709, Val MedAE=0.009744, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:54:56.355 1: SolCast DEBUG&amp;gt; Epoche 2980: Train MSE=0.000185, Val MSE=0.000344, Val MAE=0.013542, Val MedAE=0.009640, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:54:59.391 1: SolCast DEBUG&amp;gt; Epoche 3000: Train MSE=0.000185, Val MSE=0.000345, Val MAE=0.013771, Val MedAE=0.010299, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:55:15.914 1: SolCast DEBUG&amp;gt; Epoche 3100: Train MSE=0.000185, Val MSE=0.000338, Val MAE=0.013390, Val MedAE=0.009239, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:55:15.920 1: SolCast DEBUG&amp;gt; Epoche 3100: Train MSE=0.000183, Val MSE=0.000338, Val MAE=0.013390, Val MedAE=0.009239, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:55:31.223 1: SolCast DEBUG&amp;gt; Epoche 3200: Train MSE=0.000183, Val MSE=0.000374, Val MAE=0.015348, Val MedAE=0.013113, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:55:46.650 1: SolCast DEBUG&amp;gt; Epoche 3300: Train MSE=0.000183, Val MSE=0.000395, Val MAE=0.015892, Val MedAE=0.013867, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:55:55.663 1: SolCast DEBUG&amp;gt; Epoche 3360: Train MSE=0.000178, Val MSE=0.000336, Val MAE=0.013102, Val MedAE=0.009038, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:55:57.156 1: SolCast DEBUG&amp;gt; Epoche 3370: Train MSE=0.000178, Val MSE=0.000328, Val MAE=0.013027, Val MedAE=0.008576, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 18:56:01.837 1: SolCast DEBUG&amp;gt; Epoche 3400: Train MSE=0.000178, Val MSE=0.000331, Val MAE=0.013966, Val MedAE=0.010989, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:56:18.127 1: SolCast DEBUG&amp;gt; Epoche 3500: Train MSE=0.000178, Val MSE=0.000317, Val MAE=0.013546, Val MedAE=0.010578, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:56:33.705 1: SolCast DEBUG&amp;gt; Epoche 3600: Train MSE=0.000178, Val MSE=0.000326, Val MAE=0.013924, Val MedAE=0.011087, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:56:49.380 1: SolCast DEBUG&amp;gt; Epoche 3700: Train MSE=0.000178, Val MSE=0.000313, Val MAE=0.013647, Val MedAE=0.011350, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:57:04.360 1: SolCast DEBUG&amp;gt; Epoche 3800: Train MSE=0.000178, Val MSE=0.000315, Val MAE=0.013759, Val MedAE=0.011353, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:57:20.079 1: SolCast DEBUG&amp;gt; Epoche 3900: Train MSE=0.000178, Val MSE=0.000317, Val MAE=0.013889, Val MedAE=0.011544, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:57:36.568 1: SolCast DEBUG&amp;gt; Epoche 4000: Train MSE=0.000178, Val MSE=0.000303, Val MAE=0.013266, Val MedAE=0.010514, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:57:51.815 1: SolCast DEBUG&amp;gt; Epoche 4100: Train MSE=0.000178, Val MSE=0.000297, Val MAE=0.013051, Val MedAE=0.010491, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:58:07.665 1: SolCast DEBUG&amp;gt; Epoche 4200: Train MSE=0.000178, Val MSE=0.000298, Val MAE=0.013165, Val MedAE=0.010657, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:58:22.874 1: SolCast DEBUG&amp;gt; Epoche 4300: Train MSE=0.000178, Val MSE=0.000299, Val MAE=0.012652, Val MedAE=0.009298, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:58:39.872 1: SolCast DEBUG&amp;gt; Epoche 4400: Train MSE=0.000178, Val MSE=0.000299, Val MAE=0.013357, Val MedAE=0.010952, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:58:55.060 1: SolCast DEBUG&amp;gt; Epoche 4500: Train MSE=0.000178, Val MSE=0.000293, Val MAE=0.012888, Val MedAE=0.010075, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:59:10.645 1: SolCast DEBUG&amp;gt; Epoche 4600: Train MSE=0.000178, Val MSE=0.000296, Val MAE=0.013170, Val MedAE=0.010801, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:59:26.299 1: SolCast DEBUG&amp;gt; Epoche 4700: Train MSE=0.000178, Val MSE=0.000289, Val MAE=0.012813, Val MedAE=0.010297, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:59:41.390 1: SolCast DEBUG&amp;gt; Epoche 4800: Train MSE=0.000178, Val MSE=0.000288, Val MAE=0.012730, Val MedAE=0.010022, Bit_Fail=0&lt;br /&gt;
2026.01.01 18:59:58.018 1: SolCast DEBUG&amp;gt; Epoche 4900: Train MSE=0.000178, Val MSE=0.000288, Val MAE=0.012927, Val MedAE=0.010486, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:00:16.580 1: SolCast DEBUG&amp;gt; Epoche 5000: Train MSE=0.000178, Val MSE=0.000300, Val MAE=0.013538, Val MedAE=0.011570, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:00:22.430 1: VRMAPI DEBUG&amp;gt; start add AI raw data for hour: 19&lt;br /&gt;
2026.01.01 19:00:22.434 1: VRMAPI DEBUG&amp;gt; AI raw add - 1 entities added to raw data pool (set verbose 4 for output more detail)&lt;br /&gt;
2026.01.01 19:00:22.507 1: VRMAPI DEBUG&amp;gt; AI raw data saved into file: ./FHEM/FhemUtils/AIraw_SolarForecast_VRMAPI&lt;br /&gt;
2026.01.01 19:00:23.036 1: SolCast DEBUG&amp;gt; start add AI raw data for hour: 19&lt;br /&gt;
2026.01.01 19:00:23.041 1: SolCast DEBUG&amp;gt; AI raw add - 1 entities added to raw data pool (set verbose 4 for output more detail)&lt;br /&gt;
2026.01.01 19:00:23.490 1: SolCast DEBUG&amp;gt; AI raw data saved into file: ./FHEM/FhemUtils/AIraw_SolarForecast_SolCast&lt;br /&gt;
2026.01.01 19:00:25.468 1: openMeteo DEBUG&amp;gt; start add AI raw data for hour: 19&lt;br /&gt;
2026.01.01 19:00:25.471 1: openMeteo DEBUG&amp;gt; AI raw add - 1 entities added to raw data pool (set verbose 4 for output more detail)&lt;br /&gt;
2026.01.01 19:00:25.529 1: openMeteo DEBUG&amp;gt; AI raw data saved into file: ./FHEM/FhemUtils/AIraw_SolarForecast_openMeteo&lt;br /&gt;
2026.01.01 19:00:36.434 1: SolCast DEBUG&amp;gt; Epoche 5100: Train MSE=0.000178, Val MSE=0.000287, Val MAE=0.012656, Val MedAE=0.009749, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:00:52.824 1: SolCast DEBUG&amp;gt; Epoche 5200: Train MSE=0.000178, Val MSE=0.000315, Val MAE=0.014053, Val MedAE=0.012264, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:01:08.326 1: SolCast DEBUG&amp;gt; Epoche 5300: Train MSE=0.000178, Val MSE=0.000291, Val MAE=0.013064, Val MedAE=0.010484, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:01:18.912 1: SolCast DEBUG&amp;gt; Early stopping bei Epoche 5370 (no improvement since 2000 epochs)&lt;br /&gt;
2026.01.01 19:01:18.914 1: === Snapshot-Statistik ===&lt;br /&gt;
2026.01.01 19:01:18.916 1: Metric-Improvement Snapshots: 64 (letzte Epoche: 3370)&lt;br /&gt;
2026.01.01 19:01:18.918 1: Bit-Improvement Snapshots:    3 (letzte Epoche: 159)&lt;br /&gt;
2026.01.01 19:01:18.919 1: Bit-Tradeoff Snapshots:       0 (letzte Epoche: 0)&lt;br /&gt;
2026.01.01 19:01:18.925 1: SolCast DEBUG&amp;gt; Best Snapshot reloaded from Epoche 3370: Train MSE=0.000178, Val MSE=0.000328, Val MAE=0.013027, Val MedAE=0.008576, Bit_Fail=0,&lt;br /&gt;
2026.01.01 19:01:18.927 1: SolCast DEBUG&amp;gt; Run Validation Test with 20% of Input data ...&lt;br /&gt;
2026.01.01 19:01:18.969 1: SolCast DEBUG&amp;gt; Validation finished - Best Training MSE=0.000178, Validation MSE=0.000328, Validation Bit_Fail=0&lt;br /&gt;
2026.01.01 19:01:18.971 1: SolCast DEBUG&amp;gt; Retrain check -&amp;gt; &lt;br /&gt;
-- In Normalization Space: -- &lt;br /&gt;
Train MSE=0.000178 &lt;br /&gt;
Val MSE=0.000328 &lt;br /&gt;
Val Mean=0.0002956156 &lt;br /&gt;
VAL/TRAIN MSE Ratio=1.837433 (limit=2.5) &lt;br /&gt;
Diff=0.000149 (limit=0.005) &lt;br /&gt;
ValStd=0.0000173294 (limit=7.39038913958514e-05) &lt;br /&gt;
-- At Original Scale: -- &lt;br /&gt;
MAE=214.560321844596 &lt;br /&gt;
RMSE/MAE=1.3893 (limit=1.5) &lt;br /&gt;
Slope=0.916647 (limit=0.7 .. 1.3) &lt;br /&gt;
Bias=2.25 (limit=+-107.280160922298) &lt;br /&gt;
R2=0.884124888835566 &lt;br /&gt;
P95=585.2166 (limit=858.241287378382) &lt;br /&gt;
P99=942.9805 (limit=1716.48257475676) &lt;br /&gt;
-- Robustness Indicators: -- &lt;br /&gt;
RMSE relative=64 (limit=20) &lt;br /&gt;
BitFail=0 (limit=5) &lt;br /&gt;
BitFailRate=0.0000 (limit=0.1) &lt;br /&gt;
-&amp;gt; Retrain&lt;br /&gt;
2026.01.01 19:01:18.979 1: SolCast DEBUG&amp;gt; Retry attempt 3 with Seed=16689959&lt;br /&gt;
2026.01.01 19:01:18.985 1: SolCast DEBUG&amp;gt; AI FANN Training started with Params:&lt;br /&gt;
num input datasets=7314, &lt;br /&gt;
training algo=FANN_TRAIN_INCREMENTAL, &lt;br /&gt;
output AF=LINEAR, &lt;br /&gt;
hidden AF=SIGMOID, &lt;br /&gt;
hidden Neurons=80,40,20, &lt;br /&gt;
hidden steepness=0.9, &lt;br /&gt;
Epoches=15000, &lt;br /&gt;
mse_error=0.001, &lt;br /&gt;
learning rate=0.00500, &lt;br /&gt;
learning momentum=0.7, &lt;br /&gt;
Data sharing=split after shuffle of training data and use AI internal shuffle (Train=5851, Test=1462), &lt;br /&gt;
Data shuffle=2 (period=10)&lt;br /&gt;
2026.01.01 19:01:19.145 1: SolCast DEBUG&amp;gt; Epoche 1: Train MSE=0.002202, Val MSE=0.002839, Val MAE=0.031937, Val MedAE=0.027914, Bit_Fail=2 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 19:01:25.133 1: SolCast DEBUG&amp;gt; Epoche 40: Train MSE=0.002098, Val MSE=0.002825, Val MAE=0.031158, Val MedAE=0.027367, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:27.800 1: SolCast DEBUG&amp;gt; Epoche 57: Train MSE=0.001969, Val MSE=0.002810, Val MAE=0.029915, Val MedAE=0.021870, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:27.982 1: SolCast DEBUG&amp;gt; Epoche 58: Train MSE=0.001947, Val MSE=0.002786, Val MAE=0.029801, Val MedAE=0.021464, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:28.134 1: SolCast DEBUG&amp;gt; Epoche 59: Train MSE=0.001921, Val MSE=0.002758, Val MAE=0.029673, Val MedAE=0.020903, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:28.609 1: SolCast DEBUG&amp;gt; Epoche 62: Train MSE=0.001810, Val MSE=0.002716, Val MAE=0.029480, Val MedAE=0.017887, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:28.767 1: SolCast DEBUG&amp;gt; Epoche 63: Train MSE=0.001761, Val MSE=0.002660, Val MAE=0.029224, Val MedAE=0.017446, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:28.915 1: SolCast DEBUG&amp;gt; Epoche 64: Train MSE=0.001706, Val MSE=0.002597, Val MAE=0.028944, Val MedAE=0.016968, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:29.063 1: SolCast DEBUG&amp;gt; Epoche 65: Train MSE=0.001645, Val MSE=0.002528, Val MAE=0.028652, Val MedAE=0.016879, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:29.207 1: SolCast DEBUG&amp;gt; Epoche 66: Train MSE=0.001581, Val MSE=0.002455, Val MAE=0.028362, Val MedAE=0.016529, Bit_Fail=2 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:34.406 1: SolCast DEBUG&amp;gt; Epoche 100: Train MSE=0.001581, Val MSE=0.001674, Val MAE=0.026943, Val MedAE=0.019938, Bit_Fail=1&lt;br /&gt;
2026.01.01 19:01:41.897 1: SolCast DEBUG&amp;gt; Epoche 149: Train MSE=0.000574, Val MSE=0.000953, Val MAE=0.021557, Val MedAE=0.017213, Bit_Fail=1 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 19:01:43.755 1: SolCast DEBUG&amp;gt; Epoche 160: Train MSE=0.000466, Val MSE=0.000806, Val MAE=0.019501, Val MedAE=0.014848, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:43.926 1: SolCast DEBUG&amp;gt; Epoche 161: Train MSE=0.000458, Val MSE=0.000792, Val MAE=0.019351, Val MedAE=0.014777, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:44.118 1: SolCast DEBUG&amp;gt; Epoche 162: Train MSE=0.000451, Val MSE=0.000778, Val MAE=0.019209, Val MedAE=0.014629, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:44.334 1: SolCast DEBUG&amp;gt; Epoche 163: Train MSE=0.000444, Val MSE=0.000764, Val MAE=0.019075, Val MedAE=0.014565, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:44.504 1: SolCast DEBUG&amp;gt; Epoche 164: Train MSE=0.000438, Val MSE=0.000752, Val MAE=0.018948, Val MedAE=0.014360, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:44.716 1: SolCast DEBUG&amp;gt; Epoche 165: Train MSE=0.000432, Val MSE=0.000740, Val MAE=0.018829, Val MedAE=0.014227, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:44.952 1: SolCast DEBUG&amp;gt; Epoche 166: Train MSE=0.000426, Val MSE=0.000729, Val MAE=0.018714, Val MedAE=0.014165, Bit_Fail=1 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:45.151 1: SolCast DEBUG&amp;gt; Epoche 167: Train MSE=0.000421, Val MSE=0.000718, Val MAE=0.018605, Val MedAE=0.014070, Bit_Fail=0 -&amp;gt; Snap saved (bit improved)&lt;br /&gt;
2026.01.01 19:01:45.311 1: SolCast DEBUG&amp;gt; Epoche 168: Train MSE=0.000416, Val MSE=0.000708, Val MAE=0.018500, Val MedAE=0.013993, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:45.475 1: SolCast DEBUG&amp;gt; Epoche 169: Train MSE=0.000411, Val MSE=0.000699, Val MAE=0.018400, Val MedAE=0.013928, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:50.312 1: SolCast DEBUG&amp;gt; Epoche 200: Train MSE=0.000411, Val MSE=0.000558, Val MAE=0.017252, Val MedAE=0.013991, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:01:50.478 1: SolCast DEBUG&amp;gt; Epoche 201: Train MSE=0.000341, Val MSE=0.000558, Val MAE=0.017237, Val MedAE=0.013915, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:50.920 1: SolCast DEBUG&amp;gt; Epoche 204: Train MSE=0.000338, Val MSE=0.000557, Val MAE=0.017191, Val MedAE=0.013805, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:51.226 1: SolCast DEBUG&amp;gt; Epoche 206: Train MSE=0.000337, Val MSE=0.000556, Val MAE=0.017163, Val MedAE=0.013746, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:58.095 1: SolCast DEBUG&amp;gt; Epoche 250: Train MSE=0.000319, Val MSE=0.000554, Val MAE=0.016637, Val MedAE=0.013530, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:01:58.382 1: SolCast DEBUG&amp;gt; Epoche 252: Train MSE=0.000318, Val MSE=0.000553, Val MAE=0.016627, Val MedAE=0.013499, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:02:00.397 1: SolCast DEBUG&amp;gt; Epoche 266: Train MSE=0.000315, Val MSE=0.000552, Val MAE=0.016535, Val MedAE=0.013373, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:02:06.185 1: SolCast DEBUG&amp;gt; Epoche 300: Train MSE=0.000315, Val MSE=0.000521, Val MAE=0.016463, Val MedAE=0.014001, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:02:17.223 1: SolCast DEBUG&amp;gt; Epoche 371: Train MSE=0.000296, Val MSE=0.000522, Val MAE=0.016217, Val MedAE=0.013366, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:02:21.515 1: SolCast DEBUG&amp;gt; Epoche 400: Train MSE=0.000296, Val MSE=0.000500, Val MAE=0.016347, Val MedAE=0.013895, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:02:23.239 1: SolCast DEBUG&amp;gt; Epoche 410: Train MSE=0.000290, Val MSE=0.000518, Val MAE=0.016152, Val MedAE=0.013203, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:02:23.555 1: SolCast DEBUG&amp;gt; Epoche 412: Train MSE=0.000290, Val MSE=0.000517, Val MAE=0.016144, Val MedAE=0.013196, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:02:24.223 1: SolCast DEBUG&amp;gt; Epoche 416: Train MSE=0.000289, Val MSE=0.000516, Val MAE=0.016133, Val MedAE=0.013144, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:02:36.913 1: SolCast DEBUG&amp;gt; Epoche 500: Train MSE=0.000289, Val MSE=0.000513, Val MAE=0.016033, Val MedAE=0.012459, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:02:36.920 1: SolCast DEBUG&amp;gt; Epoche 500: Train MSE=0.000274, Val MSE=0.000513, Val MAE=0.016033, Val MedAE=0.012459, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:02:37.941 1: SolCast DEBUG&amp;gt; Epoche 507: Train MSE=0.000273, Val MSE=0.000512, Val MAE=0.016016, Val MedAE=0.012419, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:02:52.279 1: SolCast DEBUG&amp;gt; Epoche 600: Train MSE=0.000273, Val MSE=0.000491, Val MAE=0.015793, Val MedAE=0.012659, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:03:07.863 1: SolCast DEBUG&amp;gt; Epoche 700: Train MSE=0.000273, Val MSE=0.000531, Val MAE=0.017652, Val MedAE=0.014846, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:03:22.755 1: SolCast DEBUG&amp;gt; Epoche 800: Train MSE=0.000273, Val MSE=0.000485, Val MAE=0.015777, Val MedAE=0.012388, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:03:22.761 1: SolCast DEBUG&amp;gt; Epoche 800: Train MSE=0.000246, Val MSE=0.000485, Val MAE=0.015777, Val MedAE=0.012388, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:03:38.201 1: SolCast DEBUG&amp;gt; Epoche 900: Train MSE=0.000246, Val MSE=0.000489, Val MAE=0.015804, Val MedAE=0.012387, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:03:53.934 1: SolCast DEBUG&amp;gt; Epoche 1000: Train MSE=0.000246, Val MSE=0.000491, Val MAE=0.016320, Val MedAE=0.012996, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:04:12.553 1: SolCast DEBUG&amp;gt; Epoche 1100: Train MSE=0.000246, Val MSE=0.000500, Val MAE=0.016762, Val MedAE=0.013013, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:04:29.863 1: SolCast DEBUG&amp;gt; Epoche 1200: Train MSE=0.000246, Val MSE=0.000472, Val MAE=0.015815, Val MedAE=0.012588, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:04:39.395 1: SolCast DEBUG&amp;gt; Epoche 1240: Train MSE=0.000226, Val MSE=0.000476, Val MAE=0.015690, Val MedAE=0.012238, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:04:44.449 1: SolCast DEBUG&amp;gt; Epoche 1260: Train MSE=0.000226, Val MSE=0.000472, Val MAE=0.015617, Val MedAE=0.012095, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:04:54.273 1: SolCast DEBUG&amp;gt; Epoche 1300: Train MSE=0.000226, Val MSE=0.000469, Val MAE=0.015375, Val MedAE=0.012019, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:04:54.283 1: SolCast DEBUG&amp;gt; Epoche 1300: Train MSE=0.000225, Val MSE=0.000469, Val MAE=0.015375, Val MedAE=0.012019, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:05:19.860 1: SolCast DEBUG&amp;gt; Epoche 1400: Train MSE=0.000225, Val MSE=0.000476, Val MAE=0.016232, Val MedAE=0.012583, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:05:46.230 1: SolCast DEBUG&amp;gt; Epoche 1500: Train MSE=0.000225, Val MSE=0.000460, Val MAE=0.015477, Val MedAE=0.012145, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:06:01.555 1: SolCast DEBUG&amp;gt; Epoche 1560: Train MSE=0.000215, Val MSE=0.000450, Val MAE=0.015175, Val MedAE=0.011698, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:06:11.656 1: SolCast DEBUG&amp;gt; Epoche 1600: Train MSE=0.000215, Val MSE=0.000446, Val MAE=0.015338, Val MedAE=0.011925, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:06:19.086 1: SolCast DEBUG&amp;gt; Epoche 1630: Train MSE=0.000213, Val MSE=0.000443, Val MAE=0.015005, Val MedAE=0.011380, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:06:37.018 1: SolCast DEBUG&amp;gt; Epoche 1700: Train MSE=0.000213, Val MSE=0.000456, Val MAE=0.016104, Val MedAE=0.012245, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:06:41.728 1: SolCast DEBUG&amp;gt; Epoche 1720: Train MSE=0.000209, Val MSE=0.000437, Val MAE=0.014979, Val MedAE=0.011226, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:06:54.098 1: SolCast DEBUG&amp;gt; Epoche 1770: Train MSE=0.000208, Val MSE=0.000428, Val MAE=0.014866, Val MedAE=0.011051, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:07:01.420 1: SolCast DEBUG&amp;gt; Epoche 1800: Train MSE=0.000208, Val MSE=0.000421, Val MAE=0.014909, Val MedAE=0.011181, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:07:09.022 1: SolCast DEBUG&amp;gt; Epoche 1830: Train MSE=0.000206, Val MSE=0.000425, Val MAE=0.014835, Val MedAE=0.010975, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:07:18.661 1: SolCast DEBUG&amp;gt; Epoche 1870: Train MSE=0.000205, Val MSE=0.000422, Val MAE=0.014635, Val MedAE=0.010337, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:07:26.451 1: SolCast DEBUG&amp;gt; Epoche 1900: Train MSE=0.000205, Val MSE=0.000421, Val MAE=0.015039, Val MedAE=0.011242, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:07:35.709 1: SolCast DEBUG&amp;gt; Epoche 1950: Train MSE=0.000204, Val MSE=0.000412, Val MAE=0.014563, Val MedAE=0.010315, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:07:43.401 1: SolCast DEBUG&amp;gt; Epoche 2000: Train MSE=0.000204, Val MSE=0.000478, Val MAE=0.017001, Val MedAE=0.013903, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:07:59.225 1: SolCast DEBUG&amp;gt; Epoche 2100: Train MSE=0.000204, Val MSE=0.000400, Val MAE=0.014424, Val MedAE=0.010221, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:07:59.231 1: SolCast DEBUG&amp;gt; Epoche 2100: Train MSE=0.000200, Val MSE=0.000400, Val MAE=0.014424, Val MedAE=0.010221, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:08:14.654 1: SolCast DEBUG&amp;gt; Epoche 2200: Train MSE=0.000200, Val MSE=0.000399, Val MAE=0.014978, Val MedAE=0.011324, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:08:28.453 1: SolCast DEBUG&amp;gt; Epoche 2290: Train MSE=0.000196, Val MSE=0.000390, Val MAE=0.014290, Val MedAE=0.009855, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:08:29.937 1: SolCast DEBUG&amp;gt; Epoche 2300: Train MSE=0.000196, Val MSE=0.000391, Val MAE=0.014139, Val MedAE=0.009359, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:08:46.992 1: SolCast DEBUG&amp;gt; Epoche 2400: Train MSE=0.000196, Val MSE=0.000429, Val MAE=0.016088, Val MedAE=0.013370, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:08:59.193 1: SolCast DEBUG&amp;gt; Epoche 2480: Train MSE=0.000193, Val MSE=0.000378, Val MAE=0.014148, Val MedAE=0.009492, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:09:02.241 1: SolCast DEBUG&amp;gt; Epoche 2500: Train MSE=0.000193, Val MSE=0.000384, Val MAE=0.014816, Val MedAE=0.011437, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:09:18.312 1: SolCast DEBUG&amp;gt; Epoche 2600: Train MSE=0.000193, Val MSE=0.000373, Val MAE=0.014435, Val MedAE=0.010892, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:09:27.592 1: SolCast DEBUG&amp;gt; Epoche 2660: Train MSE=0.000190, Val MSE=0.000367, Val MAE=0.013899, Val MedAE=0.009407, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:09:33.631 1: SolCast DEBUG&amp;gt; Epoche 2700: Train MSE=0.000190, Val MSE=0.000364, Val MAE=0.014131, Val MedAE=0.010351, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:09:50.479 1: SolCast DEBUG&amp;gt; Epoche 2800: Train MSE=0.000190, Val MSE=0.000374, Val MAE=0.014829, Val MedAE=0.011905, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:10:06.433 1: SolCast DEBUG&amp;gt; Epoche 2900: Train MSE=0.000190, Val MSE=0.000358, Val MAE=0.013816, Val MedAE=0.009626, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:10:17.130 1: SolCast DEBUG&amp;gt; Epoche 2970: Train MSE=0.000184, Val MSE=0.000354, Val MAE=0.013688, Val MedAE=0.009390, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:10:21.510 1: SolCast DEBUG&amp;gt; Epoche 3000: Train MSE=0.000184, Val MSE=0.000376, Val MAE=0.015092, Val MedAE=0.012492, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:10:37.294 1: SolCast DEBUG&amp;gt; Epoche 3100: Train MSE=0.000184, Val MSE=0.000344, Val MAE=0.013896, Val MedAE=0.010700, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:10:52.935 1: SolCast DEBUG&amp;gt; Epoche 3200: Train MSE=0.000184, Val MSE=0.000340, Val MAE=0.013841, Val MedAE=0.010725, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:11:09.459 1: SolCast DEBUG&amp;gt; Epoche 3300: Train MSE=0.000184, Val MSE=0.000343, Val MAE=0.014114, Val MedAE=0.011228, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:11:25.191 1: SolCast DEBUG&amp;gt; Epoche 3400: Train MSE=0.000184, Val MSE=0.000329, Val MAE=0.013537, Val MedAE=0.010090, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:11:40.627 1: SolCast DEBUG&amp;gt; Epoche 3500: Train MSE=0.000184, Val MSE=0.000338, Val MAE=0.014317, Val MedAE=0.012038, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:11:56.504 1: SolCast DEBUG&amp;gt; Epoche 3600: Train MSE=0.000184, Val MSE=0.000338, Val MAE=0.014292, Val MedAE=0.011860, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:12:13.062 1: SolCast DEBUG&amp;gt; Epoche 3700: Train MSE=0.000184, Val MSE=0.000318, Val MAE=0.013443, Val MedAE=0.010655, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:12:28.812 1: SolCast DEBUG&amp;gt; Epoche 3800: Train MSE=0.000184, Val MSE=0.000314, Val MAE=0.013299, Val MedAE=0.010337, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:12:44.335 1: SolCast DEBUG&amp;gt; Epoche 3900: Train MSE=0.000184, Val MSE=0.000316, Val MAE=0.013177, Val MedAE=0.009737, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:12:59.748 1: SolCast DEBUG&amp;gt; Epoche 4000: Train MSE=0.000184, Val MSE=0.000344, Val MAE=0.014781, Val MedAE=0.012876, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:13:16.661 1: SolCast DEBUG&amp;gt; Epoche 4100: Train MSE=0.000184, Val MSE=0.000307, Val MAE=0.013173, Val MedAE=0.010441, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:13:31.964 1: SolCast DEBUG&amp;gt; Epoche 4200: Train MSE=0.000184, Val MSE=0.000338, Val MAE=0.013368, Val MedAE=0.008535, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:13:31.971 1: SolCast DEBUG&amp;gt; Epoche 4200: Train MSE=0.000173, Val MSE=0.000338, Val MAE=0.013368, Val MedAE=0.008535, Bit_Fail=0 -&amp;gt; Snap saved (metric improved)&lt;br /&gt;
2026.01.01 19:13:47.873 1: SolCast DEBUG&amp;gt; Epoche 4300: Train MSE=0.000173, Val MSE=0.000322, Val MAE=0.014152, Val MedAE=0.012068, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:14:02.737 1: SolCast DEBUG&amp;gt; Epoche 4400: Train MSE=0.000173, Val MSE=0.000317, Val MAE=0.013926, Val MedAE=0.011788, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:14:18.079 1: SolCast DEBUG&amp;gt; Epoche 4500: Train MSE=0.000173, Val MSE=0.000301, Val MAE=0.013120, Val MedAE=0.010500, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:14:34.780 1: SolCast DEBUG&amp;gt; Epoche 4600: Train MSE=0.000173, Val MSE=0.000300, Val MAE=0.013251, Val MedAE=0.011131, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:14:50.749 1: SolCast DEBUG&amp;gt; Epoche 4700: Train MSE=0.000173, Val MSE=0.000316, Val MAE=0.013979, Val MedAE=0.011920, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:15:07.488 1: SolCast DEBUG&amp;gt; Epoche 4800: Train MSE=0.000173, Val MSE=0.000298, Val MAE=0.013297, Val MedAE=0.011209, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:15:24.075 1: SolCast DEBUG&amp;gt; Epoche 4900: Train MSE=0.000173, Val MSE=0.000299, Val MAE=0.013338, Val MedAE=0.011219, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:15:40.613 1: SolCast DEBUG&amp;gt; Epoche 5000: Train MSE=0.000173, Val MSE=0.000301, Val MAE=0.012879, Val MedAE=0.009926, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:15:57.651 1: SolCast DEBUG&amp;gt; Epoche 5100: Train MSE=0.000173, Val MSE=0.000296, Val MAE=0.013288, Val MedAE=0.011301, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:16:13.287 1: SolCast DEBUG&amp;gt; Epoche 5200: Train MSE=0.000173, Val MSE=0.000299, Val MAE=0.013429, Val MedAE=0.011297, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:16:29.416 1: SolCast DEBUG&amp;gt; Epoche 5300: Train MSE=0.000173, Val MSE=0.000326, Val MAE=0.014362, Val MedAE=0.012558, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:16:52.624 1: SolCast DEBUG&amp;gt; Epoche 5400: Train MSE=0.000173, Val MSE=0.000293, Val MAE=0.013008, Val MedAE=0.010932, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:17:15.448 1: SolCast DEBUG&amp;gt; Epoche 5500: Train MSE=0.000173, Val MSE=0.000303, Val MAE=0.013566, Val MedAE=0.011497, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:17:36.891 1: SolCast DEBUG&amp;gt; Epoche 5600: Train MSE=0.000173, Val MSE=0.000290, Val MAE=0.012844, Val MedAE=0.010516, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:17:59.157 1: SolCast DEBUG&amp;gt; Epoche 5700: Train MSE=0.000173, Val MSE=0.000301, Val MAE=0.013589, Val MedAE=0.011589, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:18:20.531 1: SolCast DEBUG&amp;gt; Epoche 5800: Train MSE=0.000173, Val MSE=0.000289, Val MAE=0.012913, Val MedAE=0.010712, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:18:35.740 1: SolCast DEBUG&amp;gt; Epoche 5900: Train MSE=0.000173, Val MSE=0.000291, Val MAE=0.013056, Val MedAE=0.010867, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:18:51.160 1: SolCast DEBUG&amp;gt; Epoche 6000: Train MSE=0.000173, Val MSE=0.000305, Val MAE=0.013648, Val MedAE=0.011687, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:19:08.256 1: SolCast DEBUG&amp;gt; Epoche 6100: Train MSE=0.000173, Val MSE=0.000290, Val MAE=0.012878, Val MedAE=0.010646, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:19:23.867 1: SolCast DEBUG&amp;gt; Epoche 6200: Train MSE=0.000173, Val MSE=0.000289, Val MAE=0.012900, Val MedAE=0.010677, Bit_Fail=0&lt;br /&gt;
2026.01.01 19:19:23.869 1: SolCast DEBUG&amp;gt; Early stopping bei Epoche 6200 (no improvement since 2000 epochs)&lt;br /&gt;
2026.01.01 19:19:23.871 1: === Snapshot-Statistik ===&lt;br /&gt;
2026.01.01 19:19:23.873 1: Metric-Improvement Snapshots: 47 (letzte Epoche: 4200)&lt;br /&gt;
2026.01.01 19:19:23.875 1: Bit-Improvement Snapshots:    3 (letzte Epoche: 167)&lt;br /&gt;
2026.01.01 19:19:23.877 1: Bit-Tradeoff Snapshots:       0 (letzte Epoche: 0)&lt;br /&gt;
2026.01.01 19:19:23.884 1: SolCast DEBUG&amp;gt; Best Snapshot reloaded from Epoche 4200: Train MSE=0.000173, Val MSE=0.000338, Val MAE=0.013368, Val MedAE=0.008535, Bit_Fail=0,&lt;br /&gt;
2026.01.01 19:19:23.886 1: SolCast DEBUG&amp;gt; Run Validation Test with 20% of Input data ...&lt;br /&gt;
2026.01.01 19:19:23.930 1: SolCast DEBUG&amp;gt; Validation finished - Best Training MSE=0.000173, Validation MSE=0.000338, Validation Bit_Fail=0&lt;br /&gt;
2026.01.01 19:19:23.933 1: SolCast DEBUG&amp;gt; Retrain check -&amp;gt; &lt;br /&gt;
-- In Normalization Space: -- &lt;br /&gt;
Train MSE=0.000173 &lt;br /&gt;
Val MSE=0.000338 &lt;br /&gt;
Val Mean=0.0002966460 &lt;br /&gt;
VAL/TRAIN MSE Ratio=1.953186 (limit=2.5) &lt;br /&gt;
Diff=0.000165 (limit=0.005) &lt;br /&gt;
ValStd=0.0000123896 (limit=7.41615117947988e-05) &lt;br /&gt;
-- At Original Scale: -- &lt;br /&gt;
MAE=220.184381409254 &lt;br /&gt;
RMSE/MAE=1.3759 (limit=1.5) &lt;br /&gt;
Slope=0.914758 (limit=0.7 .. 1.3) &lt;br /&gt;
Bias=-38.97 (limit=+-110.092190704627) &lt;br /&gt;
R2=0.880327221041415 &lt;br /&gt;
P95=605.3179 (limit=880.737525637016) &lt;br /&gt;
P99=868.5353 (limit=1761.47505127403) &lt;br /&gt;
-- Robustness Indicators: -- &lt;br /&gt;
RMSE relative=65 (limit=20) &lt;br /&gt;
BitFail=0 (limit=5) &lt;br /&gt;
BitFailRate=0.0000 (limit=0.1) &lt;br /&gt;
-&amp;gt; Retrain&lt;br /&gt;
2026.01.01 19:19:23.945 1: SolCast DEBUG&amp;gt; Best model after retries comes from Attempt=3 with: &lt;br /&gt;
Seed=16689959, &lt;br /&gt;
Model Slope=0.91, &lt;br /&gt;
Model Bias=-38.97, &lt;br /&gt;
VAL MedAE=140.59, &lt;br /&gt;
VAL MAE=220.18, &lt;br /&gt;
VAL RMSE=302.94, &lt;br /&gt;
VAL RMSE relative=65 %, &lt;br /&gt;
VAL RMSE_Rating=very bad, &lt;br /&gt;
VAL R2=0.88, &lt;br /&gt;
Val MSE=0.000338&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Auswertung der Trainingskennwerte ====&lt;br /&gt;
&lt;br /&gt;
Abrufbar über:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get &amp;lt;Name&amp;gt; valDecTree aiNeuralNetConState&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Modellparameter ===== &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Kennwert !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| Normierungsgrenzen || Skalierung der Eingabedaten&lt;br /&gt;
|-&lt;br /&gt;
| Trainingsdaten || Anzahl der Datensätze (Training/Validierung)&lt;br /&gt;
|-&lt;br /&gt;
| Architektur || Inputs, Hidden Layers, Outputs&lt;br /&gt;
|-&lt;br /&gt;
| Hyperparameter || Learning Rate, Momentum, BitFail‑Limit&lt;br /&gt;
|-&lt;br /&gt;
| Aktivierungen || Hidden/Output‑Aktivierungsfunktionen&lt;br /&gt;
|-&lt;br /&gt;
| Zufallsgenerator || Shuffle‑Mode und Shuffle‑Periode&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Trainingsmetriken ===== &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Kennwert !! Interpretation&lt;br /&gt;
|-&lt;br /&gt;
| bestes Modell bei Epoche || Zeitpunkt minimalen Validierungsfehlers&lt;br /&gt;
|-&lt;br /&gt;
| Training MSE / Validation MSE || Fehlermaße; sollten niedrig und ähnlich sein&lt;br /&gt;
|-&lt;br /&gt;
| Validation Bit_Fail || Anzahl fehlerhafter Klassifikationen&lt;br /&gt;
|-&lt;br /&gt;
| bester Trainingslauf || Lauf mit bestem Ergebnis&lt;br /&gt;
|-&lt;br /&gt;
| Trainingsbewertung || Qualitätsindikator (Varianz, Mittelwert)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Fehlermaße der Prognosen ===== &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Kennwert !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| MAE || mittlerer absoluter Fehler (Wh)&lt;br /&gt;
|-&lt;br /&gt;
| MedAE || medianer Fehler&lt;br /&gt;
|-&lt;br /&gt;
| RMSE || quadratischer Fehler, betont Ausreißer&lt;br /&gt;
|-&lt;br /&gt;
| MAPE || prozentualer Fehler&lt;br /&gt;
|-&lt;br /&gt;
| MdAPE || medianer prozentualer Fehler&lt;br /&gt;
|-&lt;br /&gt;
| R² || Gütemaß (0–1)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Interpretation des Beispielmodells ===== &lt;br /&gt;
&lt;br /&gt;
Die Modellkennzahlen können nach ausgführten Training mit&lt;br /&gt;
&lt;br /&gt;
 get &amp;lt;Name&amp;gt; valDecTree aiNeuralNetConState&lt;br /&gt;
&lt;br /&gt;
angezeigt werden. Eine Beispielausgabe sieht etwa so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
letztes KI-Training: 25.12.2025 03:52:41 / Laufzeit in Sekunden: 1951&lt;br /&gt;
letzte KI-Ergebnis Generierungsdauer: 20.37 ms&lt;br /&gt;
&lt;br /&gt;
=== Modellparameter ===&lt;br /&gt;
&lt;br /&gt;
Normierungsgrenzen: PV=9276 W, Hausverbrauch: Min=0 W / Max=8937 W&lt;br /&gt;
Trainingsdaten: 7760 Datensätze (Training=6208, Validierung=1552)&lt;br /&gt;
Architektur: Inputs=41, Hidden Layers=80-40-20, Outputs=1&lt;br /&gt;
Hyperparameter: Learning Rate=0.005, Momentum=0.5, BitFail-Limit=0.35&lt;br /&gt;
Aktivierungen: Hidden=SIGMOID, Steilheit=0.9, Output=LINEAR&lt;br /&gt;
Zufallsgenerator: Mode=2, Periode=10&lt;br /&gt;
&lt;br /&gt;
=== Trainingsmetriken ===&lt;br /&gt;
&lt;br /&gt;
bestes Modell bei Epoche: 8690 (von max. 15000)&lt;br /&gt;
Training MSE: 0.000&lt;br /&gt;
Validation MSE: 0.000&lt;br /&gt;
Validation Bit_Fail: 0&lt;br /&gt;
bester Trainingslauf: 2&lt;br /&gt;
Trainingsbewertung: ok (Val MSE Standard Deviation=0.000000, Val MSE Avg=0.000003)&lt;br /&gt;
&lt;br /&gt;
=== Fehlermaße der Prognosen ===&lt;br /&gt;
&lt;br /&gt;
MAE: 122.74 Wh&lt;br /&gt;
MedAE: 69.28 Wh&lt;br /&gt;
RMSE: 0.002&lt;br /&gt;
MAPE: 17.526 %&lt;br /&gt;
MdAPE: 10.611 %&lt;br /&gt;
R²: 0.847&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Interpretation dieser Daten wird im angezeigten Popup mit ausgegeben und ist diesem Fall:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 7760 Datensätze → sehr gute Basis  &lt;br /&gt;
* 80‑40‑20 Architektur → geeignet für komplexe Muster  &lt;br /&gt;
* MSE ≈ 0 → exzellente Modellanpassung  &lt;br /&gt;
* MAE 122 Wh → sehr präzise  &lt;br /&gt;
* R² = 0.847 → hohe Erklärungsqualität  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Modell ist stabil, generalisiert gut und liefert sehr brauchbare Prognosen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== DriftSlope – Bedeutung, Berechnung und Interpretation ====&lt;br /&gt;
🧩 &#039;&#039;&#039;Was ist DriftSlope?&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DriftSlope&#039;&#039;&#039; beschreibt, wie stark sich die Dynamik des Modells im Vergleich zur Realität verändert hat. &amp;lt;br&amp;gt;&lt;br /&gt;
Dynamik bedeutet hier: &#039;&#039;&#039;Wie stark steigen oder fallen die Werte im Verhältnis zueinander?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ein Modell kann also:&lt;br /&gt;
* &#039;&#039;&#039;zu flach&#039;&#039;&#039; sein (reagiert zu wenig auf Veränderungen),&lt;br /&gt;
* &#039;&#039;&#039;zu steil&#039;&#039;&#039; sein (überreagiert),&lt;br /&gt;
* oder &#039;&#039;&#039;perfekt&#039;&#039;&#039; zur Realität passen.&lt;br /&gt;
&lt;br /&gt;
DriftSlope misst genau diese Abweichung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🧮 &#039;&#039;&#039;Wie wird DriftSlope berechnet?&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
[[Datei:DriftSlope.png|right|thumb|400px|DriftSlope]]&lt;br /&gt;
&lt;br /&gt;
Die Formel lautet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DriftSlope = SlopeLive / SlopeModel&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SlopeLive&#039;&#039;&#039; = Steigung aus den letzten Live‑Daten&lt;br /&gt;
* &#039;&#039;&#039;SlopeModel&#039;&#039;&#039; = Steigung aus dem ursprünglichen Modelltraining&lt;br /&gt;
&lt;br /&gt;
Damit ist DriftSlope ein &#039;&#039;&#039;Verhältnis&#039;&#039;&#039;, kein Unterschied.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🎯 &#039;&#039;&#039;Warum ist das ein Verhältnis und keine Differenz?&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Verhältnis ist robust gegenüber Skalierung und Lastniveau. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Beispiel:&#039;&#039;&#039;&lt;br /&gt;
* Modell: Slope = 0.9 / Live: Slope = 0.9 → Verhältnis = 1.0 → &#039;&#039;&#039;perfekt&#039;&#039;&#039;&lt;br /&gt;
* Modell: 0.9 / Live: 0.45 → Verhältnis = 0.5 → &#039;&#039;&#039;Modell ist doppelt so steil wie die Realität&#039;&#039;&#039;&lt;br /&gt;
* Modell: 0.9 / Live: 1.35 → Verhältnis = 1.5 → &#039;&#039;&#039;Modell ist zu flach&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Differenz (z. B. 0.9 − 0.45 = 0.45) wäre nicht interpretierbar, weil sie nicht skaliert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
📊 &#039;&#039;&#039;Wie interpretiert man DriftSlope?&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! DriftSlope !! Bedeutung !! Interpretation&lt;br /&gt;
|-&lt;br /&gt;
| ≈ 1.0 || perfekt || Modell und Realität haben die gleiche Dynamik&lt;br /&gt;
|-&lt;br /&gt;
| 0.85 - 1.15 || leichte Abweichung || Modell ist etwas flacher oder steiler&lt;br /&gt;
|-&lt;br /&gt;
| 0.70 - 1.30 || moderate Drift || Modell reagiert spürbar anders als die Realität&lt;br /&gt;
|-&lt;br /&gt;
|  || starke Drift || Modell ist deutlich zu flach oder zu steil&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🧭 &#039;&#039;&#039;Warum ist die Richtung wichtig?&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* DriftSlope &amp;gt; 1.0  &lt;br /&gt;
::→ Live‑Dynamik ist stärker&lt;br /&gt;
::→ Modell reagiert zu wenig&lt;br /&gt;
::→ Prognosen müssen verstärkt werden&lt;br /&gt;
&lt;br /&gt;
* DriftSlope &amp;lt; 1.0  &lt;br /&gt;
::→ Live‑Dynamik ist schwächer&lt;br /&gt;
::→ Modell reagiert zu stark&lt;br /&gt;
::→ Prognosen müssen abgeschwächt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Damit steuert DriftSlope die &#039;&#039;&#039;multiplikative Korrektur&#039;&#039;&#039; des Modells.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🧠 &#039;&#039;&#039;Zusammenfassung&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DriftSlope&#039;&#039;&#039; ist ein Verhältnis:&lt;br /&gt;
&lt;br /&gt;
 DriftSlope = SlopeLive / SlopeModel&lt;br /&gt;
&lt;br /&gt;
Es zeigt:&lt;br /&gt;
* wie gut das Modell die reale Dynamik abbildet&lt;br /&gt;
* ob das Modell zu flach oder zu steil ist&lt;br /&gt;
* wie stark die Drift ist&lt;br /&gt;
* wie stark die Korrektur ausfallen soll&lt;br /&gt;
&lt;br /&gt;
DriftSlope ist damit ein zentraler Baustein der Drift‑Erkennung und der automatischen Modellkorrektur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== automatische Bias‑ und Drift‑Korrektur (Überblick) ====&lt;br /&gt;
&lt;br /&gt;
📘 Die Verbrauchs‑Prognose nutzt ein neuronales Netz, das aus historischen Verbrauchsdaten lernt. Damit die Vorhersagen auch bei veränderten Haushaltsmustern stabil und realistisch bleiben, wird das Roh‑Ergebnis des Modells bei jeder Prognoseerstellung durch zwei zusätzliche Korrekturschritte verbessert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== 🔧 1. Modell‑Bias‑Korrektur (Feinabstimmung) =====&lt;br /&gt;
&lt;br /&gt;
Das neuronale Netz kann nach dem Training einen kleinen systematischen Fehler haben – zum Beispiel leicht zu hoch oder zu niedrig liegen. Dieser Fehler wird als &amp;lt;code&amp;gt;ModelBias&amp;lt;/code&amp;gt; gemessen.&lt;br /&gt;
&lt;br /&gt;
Die Bias‑Korrektur:&lt;br /&gt;
&lt;br /&gt;
* wirkt nur im Grundlastbereich (keine Peak‑Verzerrung)&lt;br /&gt;
* ist additiv – korrigiert wird aber nicht um einen festen Wert, sondern um einen &#039;&#039;&#039;Anteil&#039;&#039;&#039; des gemessenen Bias, der von der Modellgüte abhängt&lt;br /&gt;
* wird über eine Zonenlogik gesteuert:&lt;br /&gt;
** Zone 1 (grün): Modell ist sehr stabil → 70 % des Bias werden korrigiert&lt;br /&gt;
** Zone 2 (gelb): Modell ist moderat stabil → 50 % des Bias werden korrigiert&lt;br /&gt;
** Zone 2b (nur bei bestimmten Haushaltsprofilen): 25 % des Bias werden korrigiert&lt;br /&gt;
** Zone 3 (rot): Modellqualität reicht nicht aus → keine additive Korrektur&lt;br /&gt;
&lt;br /&gt;
Damit wird das Modell feinjustiert, ohne Peaks oder Lastspitzen zu verändern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== 🌡️ 2. Drift‑Korrektur (Anpassung an aktuelles Verbrauchsverhalten) ===== &lt;br /&gt;
&lt;br /&gt;
Der Verbrauch eines Haushalts kann sich im Laufe der Zeit ändern (z. B. neue Geräte, anderes Verhalten, Jahreszeit). Die Drift‑Analyse erkennt solche Veränderungen anhand von:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftSlope&amp;lt;/code&amp;gt; – Verhältnis zwischen aktueller und zuletzt kalibrierter Regressionssteigung&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftRmseRelRatio&amp;lt;/code&amp;gt; – Verhältnis der aktuellen relativen Fehlerlage (RMSE) zur Referenz&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftBias&amp;lt;/code&amp;gt; – aktuelle systematische Verschiebung gegenüber der Referenz&lt;br /&gt;
&lt;br /&gt;
Wenn Drift erkannt wird, wird die Prognose angepasst:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;✔ Level‑Korrektur&#039;&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
Die Vorhersage wird proportional verstärkt oder abgeschwächt, je nachdem wie stark sich das aktuelle Verbrauchsniveau von der zuletzt kalibrierten Referenz unterscheidet.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;✔ Drift‑Bias&#039;&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
Ein zusätzlicher Korrekturwert wird – ebenfalls nur im Grundlastbereich – addiert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;✔ Adaptive Drift‑Gewichtung&#039;&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
Die Stärke der Drift‑Korrektur hängt dynamisch ab von:&lt;br /&gt;
* Abweichung des Slopes von der Referenz&lt;br /&gt;
* Stärke der relativen Fehlerabweichung (RMSE)&lt;br /&gt;
* allgemeiner Modellqualität (MAE)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;✔ Drift‑Zonenlogik&#039;&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
Zusätzlich wird die Drift in drei Stufen eingeteilt:&lt;br /&gt;
* Drift‑Grün: kaum Drift → nur 10 % der Level‑Korrektur wirksam&lt;br /&gt;
* Drift‑Gelb: moderater Drift → 40 % der Level‑Korrektur wirksam&lt;br /&gt;
* Drift‑Rot: starker Drift → 70 % der Level‑Korrektur wirksam&lt;br /&gt;
&lt;br /&gt;
Damit reagiert die Prognose sanft bei kleinen Veränderungen und stärker bei echten Strukturbrüchen. &#039;&#039;&#039;Nachts (00–06 Uhr)&#039;&#039;&#039; sowie bei einem frisch trainierten Modell wird die Drift‑Level‑Korrektur automatisch deaktiviert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🎯 &#039;&#039;&#039;Warum das wichtig ist&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
Ohne Bias‑ und Drift‑Korrektur würden Prognosen:&lt;br /&gt;
* bei veränderten Verbrauchsgewohnheiten zu hoch oder zu niedrig liegen&lt;br /&gt;
* Peaks falsch einschätzen&lt;br /&gt;
* langsam oder gar nicht auf neue Muster reagieren&lt;br /&gt;
&lt;br /&gt;
Mit der Korrektur:&lt;br /&gt;
* bleibt die Prognose realistisch und stabil&lt;br /&gt;
* passt sich automatisch an das aktuelle Verhalten an&lt;br /&gt;
* schützt Peaks vor Überkorrektur&lt;br /&gt;
* liefert visuell plausible Verläufe&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== 🔄 3. Rekalibrierung nach einem neuen Training (Drift‑Reset) ===== &lt;br /&gt;
&lt;br /&gt;
Nach jedem KI‑Training startet das Modell mit einem neutralen Drift‑Zustand. Das ist wichtig, weil die Drift‑Analyse auf einem Zeitfenster der jüngsten Vergangenheit basiert (standardmäßig 96 Stunden, je nach Situation automatisch zwischen 48 und 144 Stunden angepasst) – unmittelbar nach dem Training stammen diese Daten aber noch vom alten Modell.&lt;br /&gt;
&lt;br /&gt;
Damit keine falsche Drift entsteht, wird die Drift‑Pipeline automatisch zurückgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftBias&amp;lt;/code&amp;gt; wird auf 0.0 gesetzt&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftSlope&amp;lt;/code&amp;gt; wird auf 1.0 gesetzt&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftFlag&amp;lt;/code&amp;gt; wird auf &amp;lt;code&amp;gt;fresh_model&amp;lt;/code&amp;gt; gesetzt&lt;br /&gt;
* die übrigen Drift‑Kennzahlen (u. a. &amp;lt;code&amp;gt;DriftScore&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DriftRmseRelRatio&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DriftIndex&amp;lt;/code&amp;gt;) werden gelöscht und im UI als „‑&amp;quot; angezeigt, bis wieder ausreichend Live‑Daten vorliegen&lt;br /&gt;
* die Referenzwerte für die Korrektur (&amp;lt;code&amp;gt;DriftRefBias&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DriftRefSlope&amp;lt;/code&amp;gt;) werden auf die Werte aus dem aktuellen Training gesetzt&lt;br /&gt;
&lt;br /&gt;
Erkennt das System über mehrere Stunden hinweg &#039;&#039;&#039;anhaltende und plausible&#039;&#039;&#039; Drift, werden die Korrektur‑Referenzwerte sanft an die realen Verbrauchsdaten angepasst:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftRefBias&amp;lt;/code&amp;gt; ersetzt den bisherigen Referenzwert als neue Basislinie für die additive Korrektur. → Das Modell verschiebt sein Grundniveau, damit die Vorhersage im Mittel wieder stimmt.&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftRefSlope&amp;lt;/code&amp;gt; ersetzt den bisherigen Referenzwert als neue Basis für die Level‑Korrektur. → Das Modell reagiert wieder angemessen auf Verbrauchsänderungen.&lt;br /&gt;
* Die ursprünglichen Trainingswerte &amp;lt;code&amp;gt;ModelBias&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;ModelSlope&amp;lt;/code&amp;gt; bleiben davon unberührt als Referenz erhalten.&lt;br /&gt;
&lt;br /&gt;
Diese Rekalibrierung geschieht bewusst nur in kleinen, gedämpften Schritten (nie ein voller Sprung auf die Live‑Werte) und &#039;&#039;&#039;erst, wenn eine Sicherheitsprüfung sie zulässt&#039;&#039;&#039; – siehe nächster Abschnitt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== 🛡️ Schutz vor Fehlalarmen ===== &lt;br /&gt;
&lt;br /&gt;
Bevor eine Rekalibrierung tatsächlich durchgeführt wird, prüft das System die aktuelle Datenlage auf Plausibilität. Erkannt und &#039;&#039;&#039;blockiert&#039;&#039;&#039; werden unter anderem:&lt;br /&gt;
&lt;br /&gt;
* typische Nacht‑/Grundlastphasen (keine echte Drift, nur niedriger Verbrauch)&lt;br /&gt;
* unplausible oder stark schwankende Slope‑/Bias‑Werte (Hinweis auf Sensor‑ oder API‑Fehler statt echter Verhaltensänderung)&lt;br /&gt;
* Fälle, in denen das Modell zwar generell ungenau, aber &#039;&#039;&#039;nicht driftend&#039;&#039;&#039; ist (hier hilft ein Retraining mehr als eine Rekalibrierung)&lt;br /&gt;
&lt;br /&gt;
Nur wenn keiner dieser Fälle vorliegt, wird tatsächlich rekalibriert. Bleibt die Drift trotzdem über viele Stunden bestehen, meldet das System stattdessen eine Retraining‑Empfehlung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== ⏳ 4. Drift‑Sperrmechanismus (ModelAgeHours) ===== &lt;br /&gt;
&lt;br /&gt;
Damit die Drift‑Analyse nur auf echten Live‑Daten des neuen Modells basiert, wird sie erst aktiviert, wenn genügend neue Daten vorliegen.&lt;br /&gt;
&lt;br /&gt;
Das Modellalter wird automatisch berechnet:&lt;br /&gt;
* aus dem Zeitstempel des letzten Trainings&lt;br /&gt;
* und dem Zeitindex der neuesten Verbrauchsdaten&lt;br /&gt;
&lt;br /&gt;
Solange das Modell jünger als die konfigurierte Mindestreife (aktuell 6 Stunden) ist:&lt;br /&gt;
* wird keine Drift berechnet&lt;br /&gt;
* alle Drift‑Parameter bleiben neutral&lt;br /&gt;
* die Prognose nutzt nur das neuronale Netz und die Modell‑Bias‑Korrektur&lt;br /&gt;
* &amp;lt;code&amp;gt;DriftFlag = fresh_model&amp;lt;/code&amp;gt;&lt;br /&gt;
* Drift‑Kennzahlen werden im UI als „‑&amp;quot; angezeigt&lt;br /&gt;
&lt;br /&gt;
Nach Ablauf dieser Mindestzeit wird die Drift‑Analyse automatisch freigeschaltet.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🎯 &#039;&#039;&#039;Warum diese Mechanismen wichtig sind&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ohne Rekalibrierung, Sicherheitsprüfung und Sperrmechanismus würden:&lt;br /&gt;
* direkt nach dem Training falsche Drift‑Signale entstehen&lt;br /&gt;
* die Prognose durch alte Fehlerbilder verzerrt&lt;br /&gt;
* Bias‑ und Drift‑Korrektur in die falsche Richtung wirken&lt;br /&gt;
* severe‑Drift‑Alarme auftreten, obwohl das Modell frisch ist – oder obwohl nur ein Sensor gerade falsche Werte liefert&lt;br /&gt;
&lt;br /&gt;
Mit dieser Logik:&lt;br /&gt;
* startet jedes Modell neutral und stabil&lt;br /&gt;
* Drift wird erst aktiv, wenn genügend neue Live‑Daten existieren&lt;br /&gt;
* offensichtlich unplausible Datenlagen lösen keine Rekalibrierung aus&lt;br /&gt;
* die Prognose bleibt ruhig, plausibel und robust&lt;br /&gt;
* Fehlalarme werden deutlich reduziert&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&#039;&#039;Eine ausführliche, technische Beschreibung mit allen Formeln, Zonenschwellen und der zugrunde liegenden ML‑Theorie findet sich im Deep‑Dive‑Artikel: [[Driftmanagement und Bias-Korrektur im SolarForecast KI-Prognosesystem]]&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Modulinterne Datenstrukturen ==&lt;br /&gt;
Das Modul speichert die verschiedenen historischen und aktuellen Daten wie PV-Prognose, Witterungsdaten (Regen, Bewölkung), Strahlungsdaten, Einspeisung, Bezug, reale Erzeugungsdaten und vieles mehr zur Laufzeit im Arbeitsspeicher. Dadurch ist die Verarbeitung dieser Daten im Vergleich zu Lesevorgängen aus dem Filesystem bzw. einer Datenbank sehr performant. Allerdings würden diese Daten bei einem FHEM Absturz bzw. bei einem regulären Shutdown verlorengehen.&lt;br /&gt;
&lt;br /&gt;
Deswegen werden die relevanten Daten regelmäßig in Dateien gesichert und bei Bedarf wiederhergestellt. Diese Dateien befinden sich im Verzeichnis &#039;&#039;&#039;../fhem/FHEM/FhemUtils&#039;&#039;&#039; und heißen &#039;&#039;&#039;.*_SolarForecast_.*&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Die Daten werden in jedem Zyklus der Zentralschleife (CentralTask) gesammelt bzw. berechnet. Der Zyklus wird mit dem Attribut &#039;&#039;&#039;plantControl-&amp;gt;cycleInterval&#039;&#039;&#039; eingestellt.&lt;br /&gt;
&lt;br /&gt;
Zur Laufzeit können diese Daten über get-Kommandos abgerufen werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get ... pvHistory [Tag]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der pvHistory Datenspeicher enthält die vergangenen Kennwerte der letzten 31 Tage mit einer Genauigkeit von einer Stunde. Es werden die Prognosewerte für Erzeugung und Verbrauch, die realen Werte für Erzeugung und Verbrauch sowie ebenso die Laufzeiten jedes einzelnen Verbrauchers (Consumer) festgehalten. Für jeden Tag gibt es die Stunde &amp;quot;99&amp;quot; die eine Summierung der Stundenwerte des Tages bzw. Sonderschlüssel enthält.&lt;br /&gt;
&lt;br /&gt;
Bei Bedarf lässt sich mit dem Befehl &amp;quot;set ... reset pvHistory&amp;quot; der gesamte Inhalt des Speichers löschen (nicht empfohlen). Selektiver funktioniert die Datenlöschung mit &amp;quot;set ... reset pvHistory &amp;lt;Tag&amp;gt;&amp;quot; (Daten eines bestimmten Tages löschen) bzw. &amp;quot;set ... reset pvHistory &amp;lt;Tag&amp;gt; &amp;lt;Stunde&amp;gt;&amp;quot; (Daten der Stunde  eines bestimmten Tages löschen). Die letzten beiden Kommandos müssen über die Kommandozeile im Browser ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get ... pvCircular &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Ringspeicher enthält Daten der letzten 24 Stunden sowie fortwährend berechnete Werte wie Korrekturfaktoren der PV-Erzeugung und Prognosequalität.&lt;br /&gt;
Neue Stundenwerte des Tages überschreiben die gespeicherten Schüssel des vorangegangenen Tages sofern es sich nicht um fortwährend berechnete Werte handelt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get ... nextHours&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Speicher enthält sämtliche Prognosewerte der kommenden Stunden beginnend mit der aktuellen Stunde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get ... radiationApiData&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Abhängig von der ausgewählten Strahlungsdaten API enthält dieser Speicher die von der API gelieferten Rohdaten sowie evtl. weitere für die Funktion benötigte Daten wie API-Keys, Response Messages, Anzahl der API Abruf und weitere.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get ... valCurrent&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Struktur wird nicht regelmäßig im Filesystem gespeichert und enthält immer aktuell gesammelte oder berechnete/gelieferte Daten wie z.B. die Autarkierate, letze Laufzeit der Zentralschleife (CentralTask), Zeit des Sonnenauf- und untergangs sowie weitere Betriebsdaten. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
get ... valConsumerMaster [XX]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zeigt die Daten der aktuell im SolarForecast Device registrierten Verbraucher. Mit der Nummer &#039;&#039;&#039;XX&#039;&#039;&#039; kann ein bestimmter Verbraucher angesprungen werden. Die Nummer korrespondiert mit dem entsprechenden &#039;&#039;&#039;consumerXX&#039;&#039;&#039; Attribut.&lt;br /&gt;
Neben anderen Betriebs- und Energiedaten werden insbesondere folgende Daten ermittelt, die für die zukünftige Planung der Verbraucherschaltzeiten relevant sind:&lt;br /&gt;
&lt;br /&gt;
* epieces - prognostizierte Energiescheiben pro Betriebsstunde &lt;br /&gt;
&lt;br /&gt;
Ausgehend von gespeicherten historischen Verbrauchsdaten des Verbrauchers wird der Energieverbrauch des Verbrauchers in seiner ersten Betriebsstunde prognostiziert, was insbesondere für die Planung der optimalen Startzeit des Verbrauchers in Bezug zu der prognostizierten PV Energie und den Verbrauchswerten weiterer vorhandener bzw. zu planender Verbraucher Berücksichtigung findet. Weitere Informationen zur Verbrauchersteuerung in diesem  [[#Verbrauchersteuerung_-_Registrieren_und_visualisieren_von_Verbrauchern|Abschnitt]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Schnittstelle für Modulautoren bzw. eigenen Code ===&lt;br /&gt;
&lt;br /&gt;
Die im vorherigen Artikel beschriebenen internen Datenstrukturen können durch externen Code abgefragt und ausgewertet werden.&lt;br /&gt;
Dazu stehen die folgenden Funktionen zur Verfügung. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]BatteryVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;Bn&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... valBattery&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]CurrentVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... valCurrent&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]InverterVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;Nr&amp;gt;&#039;, &amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... valInverter&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]ProducerVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;Nr&amp;gt;&#039;, &amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... valProducer&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]HistoryVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;Day&amp;gt;&#039;, &#039;&amp;lt;HoD&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... pvHistory&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]CircularVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;HoD&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... pvCircular&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]NexthoursVal (&#039;&amp;lt;Name&amp;gt;&#039;, &amp;lt;nhr&amp;gt;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... nextHours&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]ConsumerVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;Nr&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... valConsumerMaster&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]RadiationAPIVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;String&amp;gt;&#039;, &#039;&amp;lt;DateTime&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... radiationApiData&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]WeatherAPIVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;APIname&amp;gt;&#039;, &#039;&amp;lt;TimeCode&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... weatherApiData&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]StatusAPIVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;APIname&amp;gt;&#039;, &#039;&amp;lt;QTag&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... statusApiData&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
::* [FHEM::SolarForecast::]StringVal (&#039;&amp;lt;Name&amp;gt;&#039;, &#039;&amp;lt;String&amp;gt;&#039;, &#039;&amp;lt;Key&amp;gt;&#039;, &amp;lt;default&amp;gt;) &amp;lt;br&amp;gt; entspricht der Abfrage mit &amp;quot;get ... valStrings&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Angabe des Packages (FHEM::SolarForecast::) ist nur notwendig wenn die Funktionen von außerhalb des SolarForecast-Devices aufgerufen werden. Innerhalb des Devices (Code-Ausführung im Attribut &#039;&#039;ctrlUserExitFn&#039;&#039;) kann darauf verzichtet werden.&lt;br /&gt;
&lt;br /&gt;
Die Bedeutung der Platzhalter sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     &amp;lt;Name&amp;gt;     - Name des SolarForecast Devices&lt;br /&gt;
     &amp;lt;Day&amp;gt;      - abzufragender Tag (01 - 31)&lt;br /&gt;
     &amp;lt;Bn&amp;gt;       - Batterie Nummer (01, 02, ...)&lt;br /&gt;
     &amp;lt;DateTime&amp;gt; - Startzeit der Form YYYY-MM-DD hh:00:00&lt;br /&gt;
     &amp;lt;TimeCode&amp;gt; - Zeitwert der Form fcX_XX (z.B. fc1_19)&lt;br /&gt;
     &amp;lt;APIname&amp;gt;  - Hauptname der API gemäß setupWeatherDev1 (z.B. OpenMeteo)&lt;br /&gt;
     &amp;lt;String&amp;gt;   - Name des PV-Modulstrings wie im Attribut &#039;setupInverterStrings&#039;&lt;br /&gt;
     &amp;lt;QTag&amp;gt;     - Question Tag, z.B. &#039;?All&#039;&lt;br /&gt;
     &amp;lt;Nr&amp;gt;       - laufende Nummer des Verbrauchers / Gerätes (01, 02, 03, 04,...)&lt;br /&gt;
     &amp;lt;HoD&amp;gt;      - abzufragende Stunde (01 - 24, 99)&lt;br /&gt;
     &amp;lt;nhr&amp;gt;      - nächste Stunde (NextHour00, NextHour01,...)&lt;br /&gt;
     &amp;lt;Key&amp;gt;      - der abzufragende Schlüssel &lt;br /&gt;
     &amp;lt;default&amp;gt;  - def default-Rückgabewert&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Beispiel Auslesen der Batterieladestrategie und Anlegen eines Readings ====&lt;br /&gt;
&lt;br /&gt;
Als Praxisbeispiel soll die aktuelle gesetzte Ladestrategie für Batterie &amp;quot;01&amp;quot; ausgelesen und mit dem Wert ein Reading im SolarForecast Device angelegt werden. &amp;lt;br&amp;gt;&lt;br /&gt;
Dazu wird der folgende Code im Attribut &#039;&#039;ctrlUserExitFn&#039;&#039; hinterlegt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  my $wert = NexthoursVal ($name, &#039;NextHour00&#039;, &#039;strategybat01&#039;, &#039;loadRelease&#039;);&lt;br /&gt;
  storeReading (&#039;Ladestrategie&#039;, $wert);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei jedem Zyklus des SF-Devices wird der aktuelle Wert von &#039;&#039;strategybat01&#039;&#039; gelesen und im Reading &#039;&#039;Ladestrategie&#039;&#039; gespeichert. Die Paket-Definition &#039;&#039;FHEM::SolarForecast::&#039;&#039; braucht nicht verwendet werden, da der Aufruf im Attribut ctrlUserExitFn innerhalb des SolarForecast-Paketes erfolgt.&lt;br /&gt;
&lt;br /&gt;
Für andere Batterienummern ist der NexthoursVal-Schlüssel &#039;&#039;strategybat01&#039;&#039; entsprechend anzupassen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Auswerten von internen Arrays ===&lt;br /&gt;
&lt;br /&gt;
Die meisten der internen Datenstrukturen liefern bei der Abfrage einen einfachen String oder numerischen Wert der ausgewertet werden kann. Es gibt allerdings auch intern gespeicherte Wertelisten. Werden die Listenstrukturen mit den oben beschriebenen Befehlen abgefragt, wird eine Referenz auf die Liste geliefert sofern sie vorhanden ist.&lt;br /&gt;
&lt;br /&gt;
Um auf die Werte einer solchen Liste zuzugreifen, ist am Beispiel des Arrays &#039;&#039;surplusslidereg&#039;&#039; aus dem Current-Speicher (get ... valCurrent) dargestellt: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
my $splref = CurrentVal ($name, &#039;surplusslidereg&#039;, &#039;.&#039;);&lt;br /&gt;
my $spser  = ref $splref eq &#039;ARRAY&#039; ? join &#039; &#039;, @{$splref} : undef;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Variable $spser enthält bei Vorhandensein der Liste einen String, der die Listenelemente von &#039;surplusslidereg&#039; durch Leerzeichen getrennt enthält.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Backup und Wiederherstellung der Moduldaten ==&lt;br /&gt;
Neben der Datenhaltung in den Attributen und Readings des SolarForecast Devices, erzeugt jedes SolarForecast Device Dateien im Verzeichnis  &#039;&#039;&#039;../fhem/FHEM/FhemUtils&#039;&#039;&#039; mit folgenden Inhalten:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Init_SolarForecast_&amp;lt;name&amp;gt;       - initiatiale Daten die vor dem Einlesen weiterer Daten oder Attribute geladen werden &lt;br /&gt;
PVH_SolarForecast_&amp;lt;name&amp;gt;        - PV History&lt;br /&gt;
PVC_SolarForecast_&amp;lt;name&amp;gt;        - PV Circular&lt;br /&gt;
PVCfg_SolarForecast_&amp;lt;name&amp;gt;      - PV Anlagenkonfiguration&lt;br /&gt;
PVCsm_SolarForecast_&amp;lt;name&amp;gt;      - Consumer Status&lt;br /&gt;
ScApi_SolarForecast_&amp;lt;name&amp;gt;      - Strahlungswerte aus verwendeter API&lt;br /&gt;
StatApi_SolarForecast_&amp;lt;name&amp;gt;    - Statusdaten der verwendeten APIs&lt;br /&gt;
WeatherApi_SolarForecast_&amp;lt;name&amp;gt; - Wetterdaten der gewählten Wetter-API (außer DWD-Device)&lt;br /&gt;
AItra_SolarForecast_&amp;lt;name&amp;gt;      - PV-KI Entscheidungsquelle (trainierte Daten)&lt;br /&gt;
AIraw_SolarForecast_&amp;lt;name&amp;gt;      - PV-KI Input Daten = Raw Trainigsdaten&lt;br /&gt;
NeuralNet_SolarForecast_&amp;lt;name&amp;gt;  - Daten des neuronalen Netztes (KI Verbrauchsprognose)&lt;br /&gt;
Messages_SolarForecast_&amp;lt;name&amp;gt;   - Daten des Nachrichten- und Informationssystems&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Je nach Ausprägung und eingesetzten Features des SolarForecast Devices sind alle oder nur ein Teil dieser Dateien vorhanden. Dabei ist &#039;&#039;&#039;&amp;lt;name&amp;gt;&#039;&#039;&#039; der Name des SolarForecast Devices.&lt;br /&gt;
&lt;br /&gt;
Bei einem Filebackup des FHEM-Servers ist darauf zu achten, dass diese Dateien in dem Backup enthalten sind. Der Inhalt der Dateien ist nicht statisch, sondern kann sich dynamisch aktualisieren. Um im Bedarfsfall einen aktuellen Datenstand zu haben, ist mindestens ein tägliches Backup dieser Dateien empfehlenswert. Eventuell auch öfter mit Hilfe einer Versionierung welche z.B. immer die letzten drei Versionen aufbewahrt.&lt;br /&gt;
&lt;br /&gt;
Beim Start von FHEM werden bestimmte Dateien automatisch gelesen und in das SolarForecast Device importiert. &lt;br /&gt;
Der Vorgang ist mit verbose=3 im Log protokolliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
2023.10.02 09:57:07.967 3: SolCast6 - cached data &amp;quot;Initialize&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.967 3: SolCast6 - set init data writeForceType=db before load over data&lt;br /&gt;
2023.10.02 09:57:07.967 3: SolCast6 - cached data &amp;quot;pvHistory&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.969 3: SolCast6 - cached data &amp;quot;pvCircular&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.970 3: SolCast6 - cached data &amp;quot;consumerMaster&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.970 3: SolCast6 - cached data &amp;quot;radiationApiData&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.970 3: SolCast6 - cached data &amp;quot;statusApiData&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.970 3: SolCast6 - cached data &amp;quot;weatherApiData&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.974 3: SolCast6 - cached data &amp;quot;aiTrainedData&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.976 3: SolCast6 - cached data &amp;quot;aiRawData&amp;quot; restored&lt;br /&gt;
2023.10.02 09:57:07.976 3: SolCast6 - cached data &amp;quot;NeuralNetwork&amp;quot; restored for FANN type &#039;con&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Bestimmte Betriebsdaten, wie z.B. die witterungsabhängigen Korrekturfaktoren (circular) oder die KI-Daten (aitrained/airaw), bauen sich über die Zeit immer granularer auf und stellen einen wertvollen Datenbestand dar.&lt;br /&gt;
&lt;br /&gt;
Wird das SolarForecast Device gelöscht und anschließend wieder neu mit dem gleichen Namen definiert, können die bisher verfügbaren Daten sehr einfach wiederhergestellt werden:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 1. definieren des neuen SolarForecast Devices, d.h. ein einfaches &amp;quot;define &amp;lt;Name&amp;gt; SolarForecast&amp;quot;, und sichern der FHEM Konfiguration (der Konfigurationsdialog muß nicht durchgeführt werden)&lt;br /&gt;
* 2. FHEM stoppen&lt;br /&gt;
* 3. wiederherstellen der oben beschriebenen Dateien aus einem Backup in das Verzeichnis ../fhem/FHEM/FhemUtils (Überschreiben evtl. vorhandener Dateien)&lt;br /&gt;
* 4. Anpassen der Dateieigentümer und Berechtigungen: chown fhem:dialout /opt/fhem/FHEM/FhemUtils/*,  chmod 774 /opt/fhem/FHEM/FhemUtils/*&lt;br /&gt;
* 5. starten von FHEM (bestimmte Daten werden automatisch importiert)&lt;br /&gt;
* 6. mit dem Befehl &amp;quot;set &amp;lt;name&amp;gt; plantConfiguration restore&amp;quot; die Anlagenkonfiguration wiederherstellen&lt;br /&gt;
* 7. FHEM Konfiguration sichern und restarten&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
Das zuvor beschriebene Verfahren kann auch angewendet werden um das SolarForcast Device von einer FHEM Installation in eine andere Installation umzuziehen. In diesem Fall ist aber besonders darauf zu achten, vorab alle in den SF-Attributen referenzierten Devices wie Inverter, Meter oder DWD-Devices mit den zutreffenden Namen in der neuen Installation anzulegen. Weiterhin muß beachtet werden, dass die &#039;&#039;&#039;Daten nicht zwischen 32 Bit-Systemen und 64 Bit-Systemen ausgetauscht werden können&#039;&#039;&#039;. So können z.B. auf einem 32 Bit-System geschriebene Dateien auf einem 64 Bit-System nicht gelesen werden und vice versa.&lt;br /&gt;
  &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soll das neue SolarForecast Device mit einem anderen Namen oder weitere SolarForecast Devices erstellt werden, welche die Betriebsdaten des primären Devices verwenden sollen, ist wie folgt vorzugehen:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 1. definieren des neuen SolarForecast Devices, d.h. ein einfaches &amp;quot;define &amp;lt;Name&amp;gt; SolarForecast&amp;quot;, und sichern der FHEM Konfiguration (der Konfigurationsdialog muß nicht durchgeführt werden)&lt;br /&gt;
* 2. FHEM stoppen&lt;br /&gt;
* 3. wiederherstellen der oben beschriebenen Dateien aus einem Backup in das Verzeichnis ../fhem/FHEM/FhemUtils (Überschreiben evtl. vorhandener Dateien)&lt;br /&gt;
* 4. umbenenen der Dateien, wobei &amp;lt;name&amp;gt; durch den Namen des neuen SolarForecast Devices ersetzt wird&lt;br /&gt;
* 5. Anpassen der Dateieigentümer und Berechtigungen: chown fhem:dialout /opt/fhem/FHEM/FhemUtils/*,  chmod 774 /opt/fhem/FHEM/FhemUtils/*&lt;br /&gt;
* 6. starten von FHEM (bestimmte Daten werden automatisch importiert)&lt;br /&gt;
* 7. mit dem Befehl &amp;quot;set &amp;lt;name&amp;gt; plantConfiguration restore&amp;quot; die Anlagenkonfiguration wiederherstellen&lt;br /&gt;
* 8. FHEM Konfiguration sichern und restarten&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wenn sich die SolarForecast Devices hinsichtlich ihres Models oder der integrierten Consumer unterscheiden, sind die Dateien &amp;quot;PVCsm_SolarForecast_&amp;lt;name&amp;gt; &amp;quot; , &amp;quot;ScApi_SolarForecast_&amp;lt;name&amp;gt;&amp;quot; von dem Verfahren auszuschließen.&lt;br /&gt;
&lt;br /&gt;
== Batterieintegration und -steuerung ==&lt;br /&gt;
&lt;br /&gt;
=== Wie eine Batterie eingebunden wird ===&lt;br /&gt;
Wie immer muß die Batterieanlage zunächst mit einem für die Batterie spezifischen FHEM-Device in FHEM definiert sein.&lt;br /&gt;
In diesem Device werden Readings erwartet die folgende Werte bereitstellen:&lt;br /&gt;
&lt;br /&gt;
::* ein Reading welches die aktuelle Batterieladeleistung liefert&lt;br /&gt;
&lt;br /&gt;
::* ein Reading welches die aktuelle Batterieentladeleistung liefert&lt;br /&gt;
&lt;br /&gt;
::* ein Reading welches die installierte Batteriekapazität liefert (&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; dieser Schlüssel ist für die Aktivierung des Batterie SOC-Managements und die grafische Anzeige des SOC wesentlich!)&lt;br /&gt;
&lt;br /&gt;
::* ein Reading welches die bis dato vorliegende Lade-Energiemenge als fortlaufenden Zähler liefert (optional)&lt;br /&gt;
&lt;br /&gt;
::* ein Reading welches die bis dato vorliegende Entlade-Energiemenge als fortlaufenden Zähler liefert (optional)&lt;br /&gt;
&lt;br /&gt;
::* Reading welches den aktuellen Ladezustand (SOC in Prozent) liefert (optional)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Batterie, bzw. das Batteriedevice wird mit dem Attribut &#039;&#039;&#039;setupBatteryDev&#039;&#039;&#039; im SolarForecast Device registriert. Die Syntax des Attributes ist in  der Online-Hilfe zum Attribut umfassend erläutert. &lt;br /&gt;
Auch wenn manche Readings optional sind, wird empfohlen alle Werte bereitzustellen um alle Batterie-Funktionen im Modul nutzen zu können. Durch die Weiterentwicklung des Moduls können optionale Readings später auch obligatorisch werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Visualisierung der Batterie in der Balkengrafik ====&lt;br /&gt;
&lt;br /&gt;
Das Attribut &#039;&#039;&#039;setupBatteryDevXX&#039;&#039;&#039; verfügt über den Schlüssel &#039;&#039;&#039;show&#039;&#039;&#039;, mit dem die Einblendung des bzw. der Batteriesymbole in den Ebenen der Balkengrafik gesteuert werden kann:&lt;br /&gt;
[[Datei:Screenshot 2025-02-23 192002.png|right|thumb|400px|Einblendung der Batterieleiste und Darstellung des Batterie-SoC als Balkencontent in der zweiten Ebene]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 0 - keine Anzeige des Gerätes (default)&lt;br /&gt;
* 1 - Anzeige des Gerätes in der Balkengrafik Ebene 1&lt;br /&gt;
* 2 - Anzeige des Gerätes in der Balkengrafik Ebene 2 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Symbole und die Farbgebung der Batterie(n) können mittels des Schlüssels &#039;&#039;&#039;icon&#039;&#039;&#039; verändert werden. Die Online-Hilfe gibt weitere Informationen zur Ausgestaltung. &lt;br /&gt;
&lt;br /&gt;
In der Batteriedarstellung wird das Symbol der aktuellen Stunde hervorgehoben. Ein Mouse-Over zeigt wesentliche Betriebszustände der Batterie. Die Batteriesymbole vergangener Stunden zeigen mit einem Mouse-Over die erreichten SoC (State of Charge) Stände. Die kommenden Stunden visualisieren die folgenden Prognosen:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* der prognostizierte SoC unter Berücksichtigung der PV-Prognose und der [[#Aktivierung_des_Batterie_SOC-Managements|Batteriesteuerung]] sofern sie im Modul aktiviert ist.&lt;br /&gt;
* eine Freigabe bzw. Empfehlung der Batterieladung zur [[#Unterstützung_eines_netzdienlichen_Verhaltens|Unterstützung eines netzdienlichen Verhaltens]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Neben der Einblendung der Batterieleiste über der Balkengrafik selbst können bestimmte Batteriekennwerte als Balkeninhalt dargestellt werden. Die Auswahl erfolgt über das Attribut &#039;&#039;&#039;graphicBeamXContent&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Aktivierung des Batterie SOC- und Lade-Managements ===&lt;br /&gt;
Das integrierte SOC- und Lade-Management verfolgt insbesondere diese Ziele: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* den Ladezustand der Batterie(n) zu optmimieren, was besonders in den Monaten mit geringerer PV-Erzeugung einen wertvollen Beitrag zur Erhöhung der Autarkierate und Batteriepflege leisten kann&lt;br /&gt;
 &lt;br /&gt;
* eine PV-Prognose und Verbrauch optimierte Beladungssteuerung, die in den Monaten mit hoher PV-Erzeugung hilft eine evtl. Abregelung der Anlage zu verhindern, die Batterie ausgewogen über den Tag zu laden und ein netzdienliches Verhalten zu unterstützen&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Aspekte der Batteriesteuerung werden in den folgenden Abschnitten beschrieben. Sind mehrere Batterien installiert, kann die Steuerung getrennt für jede einzelne Batterie aktiviert und eingestellt werden. Dabei ist zu beachten, dass vom Modul nur Signale und Readings bereitgestellt werden, die durch eine entsprechende Routine ausgewertet werden können um spezifische Befehle zur Umsetzung der Steuerung an das Batteriesystem zu senden. &lt;br /&gt;
 &lt;br /&gt;
Für eine Aktivierung des Managements muß zunächst das Batterie-Device wie im vorigen Abschnitt im SolarForecast Device registriert werden.&lt;br /&gt;
Das Attribut &#039;&#039;&#039;ctrlBatSocManagementXX&#039;&#039;&#039; aktiviert die im Modul integrierte SOC- und Lade-Management Routine: &lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Device&amp;gt; ctrlBatSocManagementXX lowSoc=&amp;lt;Wert&amp;gt; upSoC=&amp;lt;Wert&amp;gt; [maxSoC=&amp;lt;Wert&amp;gt;] [careCycle=&amp;lt;Wert&amp;gt;] [loadAbort=&amp;lt;SoC1&amp;gt;:&amp;lt;MinPwr&amp;gt;:&amp;lt;SoC2&amp;gt;] [safetyMargin=&amp;lt;Wert&amp;gt;[:&amp;lt;Wert&amp;gt;]] ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die einzelnen Schlüssel werden der Kalkulationsroutine als Steuerungsparameter übergeben und bedeuten:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;lowSoc:unterer Mindest-SoC, die Batterie wird nicht tiefer als dieser Wert entladen (muß &amp;gt; 0 sein). Dieser Wert kann zum Beispiel dazu dienen, stets eine Mindestenergiemenge für den Fall eines Stromausfalls im öffentlichen Netz in den Batterien vorzuhalten.&lt;br /&gt;
&lt;br /&gt;
;upSoC:oberer Mindest-SoC, Der übliche Wert des optimalen SoC bewegt sich in Perioden mit hohen PV-Überschuß tendenziell zwischen &#039;lowSoC&#039; und &#039;upSoC&#039;, in Perioden mit geringer PV-Ausbeute bzw. geringem PV Energieüberschuß bewegt sich der optimale SoC tendenziell zwischen &#039;upSoC&#039; und &#039;maxSoC&#039;. Die Einstellung von upSoC=50 für ein ausgewogenes Verhalten kann als guter Startwert dienen.&lt;br /&gt;
&lt;br /&gt;
;maxSoC:maximaler Mindest-SoC, d.h. der SoC Wert der mindestens im Abstand von &#039;careCycle&#039; Tagen erreicht werden muß um den Ladungsausgleich im Speicherverbund auszuführen. Die Angabe ist optional (muß &amp;lt;= 100 sein, default: 95)&lt;br /&gt;
&lt;br /&gt;
;stepSoC: Optionale Schrittweite zur optimalen SoC-Berechnung (Battery_OptimumTargetSoC_XX) in %. Mit der Angabe &#039;stepSoC=0&#039; wird das SoC-Management deaktiviert und Battery_OptimumTargetSoC_XX auf den Wert &#039;lowSoC&#039; gesetzt. &#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Die Beziehung &#039;careCycle * stepSoC = 100&#039; sollte eingehalten werden! Wert: 0..5, default: 5 &lt;br /&gt;
&lt;br /&gt;
;careCycle:maximaler Abstand in Tagen, der zwischen zwei Ladungszuständen von mindestens &#039;maxSoC&#039; auftreten sollte. Anders formuliert legt careCycle fest, alle wieviel Tage mindestens einmal maxSoC erreicht werden sollte. Die Angabe ist optional. (default: 20)&lt;br /&gt;
&lt;br /&gt;
;lcSlot: Es wird ein tägliches Zeitfenster festgelegt, in dem die Ladesteuerung des Moduls für diese Batterie aktiv sein soll. Außerhalb des Zeitfensters wird die Batterieladung mit voller Leistung freigegeben. Das SoC-Management der Batterie ist davon nicht betroffen. Wert: &amp;lt;hh:mm&amp;gt;-&amp;lt;hh:mm&amp;gt;, default: ganztägig&lt;br /&gt;
&lt;br /&gt;
;loadAbort: definiert eine vom Anwender gewünnschte Bedingung für einen generellen Ladeabbruch und Wiederfreigabe der Lademöglichkeit. Die Abbruchbedingung ist erfüllt, wenn der angegebene SoC1 (%) erreicht bzw. überschritten ist &#039;&#039;&#039;UND&#039;&#039;&#039; die angegebene Ladeleistung &amp;lt;MinPwr&amp;gt; (W) unterschritten wurde -&amp;gt; Reading Battery_ChargeAbort_XX=1. Fällt der aktuelle SoC wieder unter den SoC2, wird Battery_ChargeAbort_XX=0 gesetzt. Ist SoC2 nicht angegeben, gilt SoC2=SoC1.  &lt;br /&gt;
&lt;br /&gt;
;loadStrategy: Abhängig von der gewählten Ladestrategie wird die Prognose der Batterieladung und ggf. die Generierung der Steuerreadings beeinflusst. Die Angabe ist optional. Wert: loadRelease | optPower | smartPower, default=loadRelease&lt;br /&gt;
	&lt;br /&gt;
;loadTarget: Optionaler Ziel-SoC in % für die Berechnung der Ladefreigabe bzw. der optimalen Ladeleistung. Der Zielwert ist eine kalkulatorische Rechengröße. Der reale SoC kann situativ in Grenzen über- oder unterschritten werden. Der höhere Wert aus Reading Battery_OptimumTargetSoC_XX und &#039;loadTarget&#039; hat für die Berechnung Vorrang. Wert: 0..100, default=100. &amp;lt;br&amp;gt; In loadTarget kann eine Zielzeit angegeben werden, wann der Ziel-SoC erreicht werden soll. Die optimale Ladeleistung wird entsprechend angepasst. Die Zeitangabe als positive Ganzzahl ist ein Absolutwert (Stunde), in der der Ziel-SoC erreicht sein soll. Ein negativer Integer (z.B. -3) besagt, dass drei Stunden vor dem [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Bestimmung_von_Sonnenaufgang_und_Sonnenuntergang|Sonnenuntergang]] des aktuellen Tages der Ziel-SoC erreicht sein soll. D.h. negative Zahlen sind Relativangaben. Generell wird der Ziel-SoC zur Wunschzeit nur dann erreicht sein, wenn genügend PV-Leistung verfügbar ist. &lt;br /&gt;
&lt;br /&gt;
;safetyMargin: Bei der Berechnung der Ladefreigabe und optimierten Ladeleistung werden Sicherheitszuschläge auf den prognostizierten Ladungsbedarf berücksichtigt. Abweichend vom Default können mit diesem Parameter individuelle Sicherheitszuschläge getrennt für die Berechnung der Ladefreigabe und optimierten Ladeleistung angegeben werden. Der erste Wert ist der Zuschlag bei der Berechnung der Ladefreigabe, der zweite Wert der Zuschlag bei der Berechnung der optimierten Ladeleistung. Beide Angaben sind Prozentwerte von 0..100.&lt;br /&gt;
&lt;br /&gt;
;weightOwnUse: Optionale Gewichtung der stündlichen Verbrauchsprognose als zusätzlich verwendbaren Anteil zur Batterieladung in %. Technisch wird der verfügbare PV-Überschuß zur Berechnung der optimierten Ladeleistung erhöht indem der kalkulierte Verbrauch um den angegebenen Prozentsatz gesenkt wird. Wert: 0..100 default: 0 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Alle SoC-Werte sind ganze Zahlen in %. Dabei gilt: &lt;br /&gt;
&lt;br /&gt;
 lowSoc &amp;lt; upSoC &amp;lt; maxSoC&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====  Erläuterung der Batterie-Steuerungsreadings ==== &lt;br /&gt;
&lt;br /&gt;
Für die Steuerung des Batteriesystems gibt es im SolarForecast einen Satz an Readings, die unterschiedliche Zustände signalisieren und für entsprechende Steuerungsaufgaben bezüglich der Batteriesysteme eingesetzt werden können. In den nachfolgenden Abschnitten werden diese Zusammenhänge noch dataillierter beschrieben.&lt;br /&gt;
&lt;br /&gt;
;Hinweis: SolarForecast stellt lediglich Steuerungsinformationen zur Verfügung. Die Umsetzung des Eingriffs in das Batteriesystem erfolgt durch den Anwender selbst über entsprechende Skripte. In den thematischen Abschnitten werden Beispiele für solche Steuerungsskripte vorgestellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Alle erstellten Readings gelten für ein Batteriesystem, es können mehrere Batteriesysteme in SolarForecast integriert sein. Die Endung &#039;&#039;XX&#039;&#039; der Readings beschreibt die Nummer des Batteriesystems und korrespondiert mit der Endung des entsprechenden Attributes &#039;&#039;ctrlBatSocManagementXX&#039;&#039; bzw. &#039;&#039;setupBatteryDevXX&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Battery_OptimumTargetSoC_XX: Mit den im Attribut &#039;&#039;ctrlBatSocManagementXX&#039;&#039; hinterlegten Parametern unter Berücksichtigung von PV- und Verbrauchsprognosen wird ein optimaler SOC-Wert errechnet. Dieser Wert dient zur Einstellung des unteren SOC des Batteriesystems.&lt;br /&gt;
&lt;br /&gt;
;Battery_ChargeRequest_XX: Dieses Reading signalisiert mit 1 eine Anforderung zur Zwangsladung der Batterie um die Batterie vor Schäden zu schützen (wenn der SOC unter ctrlBatSocManagementXX-&amp;gt;lowSoc gefallen ist) oder wenn der aktuelle SOC unter den berechneten Mindest-SOC gefallen ist.&lt;br /&gt;
&lt;br /&gt;
;Battery_ChargeUnrestricted_XX: Dieses Reading kann den Wert &#039;&#039;&#039;0&#039;&#039;&#039; oder &#039;&#039;&#039;1&#039;&#039;&#039; einnehmen. Ist der Wert 0, sollte die Batterie nur geladen werden, wenn der im Attribut &#039;&#039;plantControl-&amp;gt;feedinPowerLimit&#039;&#039; definierte Wert überschritten wird. Ist der Wert 1, sollte die Batterie mit der vollen zur Verfügung stehenden Ladeleistung angesteuert werden, um wie prognostiziert am Ende des Sonnentages die volle bzw. maximal mögliche Ladung zu erhalten. Der Fokus der Steuerung mit diesem Reading ist es, die Speicherkapazität der Batterie optimal zur Verhinderung der Überschreitung von Einspeiselimits einzusetzen und dennoch einen maximal möglichen SoC am Tagesende zu erreichen. (siehe das beschriebene [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#PV-Prognose_und_Verbrauch_optimierte_Beladungssteuerung_unter_Berücksichtigung_einer_Wirkleistungsbegrenzung|Nutzungsbeispiel]])&lt;br /&gt;
&lt;br /&gt;
;Battery_ChargeOptTargetPower_XX: Dieses Reading enthält einen Richtwert für die optimierte Ladeleistung für jede Batterie. Die Aufladung wird prognosegeführt über den gesamten Tag verteilt, wobei der Fokus auf eine kontinuierliche, aber möglichst niederige Ladeleistung gelegt wird. (siehe diesen [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#leistungsoptimierte_Beladungssteuerung_mit_dem_Fokus_geringe_Verlustleistung_und_Verschleiß|Abschnitt]])  &lt;br /&gt;
&lt;br /&gt;
;Battery_ChargeAbort_XX: Im Attribut &#039;&#039;ctrlBatSocManagementXX&#039;&#039; kann mit dem Schlüssel &#039;&#039;loadAbort&#039;&#039; eine Bedingung definiert werden, bei deren Eintritt die Ladung der Batterie abgebrochen werden soll. In diesem Fall wird &#039;&#039;Battery_ChargeAbort_XX=1&#039;&#039; gesetzt. Mit einem entsprechenden Befehl kann der Anwender das Batteriesystem anweisen den Ladevorgang abzubrechen. &lt;br /&gt;
&lt;br /&gt;
;Battery_TargetAchievable_XX: Diese Reading enthält einen Boolean Wert 0|1 und signalisiert ob der im Attribut &#039;&#039;&#039;ctrlBatSocManagementXX-&amp;gt;loadTarget&#039;&#039;&#039; gesetzte Ziel-SoC lt. Prognose am aktuellen Tag tatsächlich erreicht werden kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Nutzung des Batterie SOC-Management ====&lt;br /&gt;
&lt;br /&gt;
Oftmals wird durch die Anlagenhersteller ein hoher statischer SOC eingestellt bzw. empfohlen, der eine längere Verharrungszeit auf einem tiefen SOC-Wert verhindern soll. Allerdings wechseln sich in auch in den Herbst-, Frühlings- und Wintermonaten Zeiten mit wenig PV-Erzeugung mit Phasen stärkerer Solarstrahlung bei klarem Himmel und Sonnenschein ab.&lt;br /&gt;
&lt;br /&gt;
Ein statischer SOC würde dazu führen, dass in den erwähnten Phasen zuviel Energie in das öffentliche Netz eingespeist wird. Dies soll verhindert werden da die wertvolle Energie besser im eigenen Netz gespeichert und in Dunkelphasen verwendet werden kann. Andererseits soll die Batterie nicht zu lange auf einem tiefen SOC verbleiben und außerdem in gewissen Abständen auf einen so hohen SOC geladen werden der den internen Zellausgleich ermöglicht.&lt;br /&gt;
&lt;br /&gt;
Die SOC Kalkulationsroutine des Moduls errechnet unter Berücksichtigung des prognostizierten PV-Ertrages der kommenden Tage, des aktuellen SOC und der im Attribut &#039;&#039;&#039;ctrlBatSocManagementXX&#039;&#039;&#039; (nachfolgend beschrieben) angegebenen Steuerparameter den Vorschlag für eine optimale SOC-Einstellung. Dabei steht &#039;XX&#039; für die Nummer der Batterie, welche mit dem Attribut setupBatteryDevXX korrespondiert.&lt;br /&gt;
&lt;br /&gt;
Durch das Modul selbst findet keine Steuerung der Batterie statt. Es stellt entsprechende Readings zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::* das Reading &#039;&#039;&#039;Battery_OptimumTargetSoC_XX&#039;&#039;&#039; enthält den vom Modul berechneten optimalen SoC.&lt;br /&gt;
&lt;br /&gt;
::* das Reading &#039;&#039;&#039;Battery_ChargeRequest_XX&#039;&#039;&#039; wird auf &#039;1&#039; gesetzt, wenn der aktuelle SoC unter den optimalen SoC gefallen ist. In diesem Fall sollte die Batterie, unter Umständen mit Netzstrom, zwangsgeladen werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Readings können zur Steuerung des SoC (State of Charge) sowie zur Steuerung des verwendeten Ladestroms der Batterie verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Ermittlung des optimalen SOC erfolgt nach folgender Logik:&lt;br /&gt;
&lt;br /&gt;
# 	Ausgehend von &#039;lowSoc&#039; wird der Mindest-SoC kurz vor Sonnenuntergang um 5% inkrementiert sofern am laufenden Tag &#039;maxSoC&#039; nicht erreicht wurde und die PV-Prognose keinen hinreichenden Ertrag des kommenden Tages vorhersagt. &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# 	Wird &#039;maxSoC&#039; (wieder) erreicht, wird Mindest-SoC um 5%, aber nicht tiefer als &#039;lowSoc&#039;, verringert. Ist der berechnete Mindest-SoC größer als &#039;upSoc&#039;, wird der Mindest-SoC auf &#039;upSoc&#039; gesetzt. &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
#   Mindest-SoC wird soweit verringert, dass die prognostizierte PV Energie des aktuellen bzw. des folgenden Tages von der Batterie aufgenommen werden kann. Mindest-SoC wird typisch auf &#039;upSoc&#039; und nicht tiefer als &#039;lowSoc&#039; verringert.  &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# 	Das Modul erfasst den letzten Zeitpunkt am &#039;maxSoC&#039;-Level, um eine Ladung auf &#039;maxSoC&#039; mindestens alle &#039;careCycle&#039; Tage zu realisieren. Zu diesem Zweck wird der optimierte SoC in Abhängigkeit der Resttage bis zum nächsten &#039;careCycle&#039; Zeitpunkt derart verändert, dass durch eine tägliche 5% SoC-Steigerung &#039;maxSoC&#039; am &#039;careCycle&#039; Zeitpunkt rechnerisch erreicht wird. Wird zwischenzeitlich &#039;maxSoC&#039; erreicht, beginnt der &#039;careCycle&#039; Zeitraum erneut. &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# 	Im fünften Schritt werden die Grenzen &#039;lowSoc&#039; und &#039;upSoc&#039; berücksichtigt. &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# 	Im letzten Schritt erfolgt Generierung des Readings &#039;&#039;&#039;Battery_ChargeRequest_XX&#039;&#039;&#039; zur Signalisierung einer eventuell empfohlenen Zwangsladung auf den berechneten Min-SoC. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bei sehr wenig Erzeugungungsprognose, d.h. wenn sich der berechnete Min-SoC oberhalb von &#039;upSoC&#039; bewegt, wird &#039;upSoC&#039; eingestellt. Liegt der berechnete Min-SoC unterhalb von &#039;upSoC&#039;, ist jedoch größer als &#039;lowSoC&#039;, wird der berechnete SOC im Reading &#039;&#039;&#039;Battery_OptimumTargetSoC_XX&#039;&#039;&#039; eingestellt. Somit eignet sich die Angabe im Schlüssel &#039;upSoC&#039; um in Zeiten geringer Solarenergieerzeugung die Batterie für eine Notstromerzeugung auf mindestens diesem Wert zu halten. Sollte die PV-Prognose kurzfristig einen größeren Ertrag vorhersagen als die Batterie durch die Einhaltung von &#039;upSoC&#039; aufnehmen kann, wird der Min-SoC unter &#039;upSoC&#039; abgesenkt um möglichst allen PV-Überschuß in der Batterie zu speichern und somit dem Eigenverbrauch zuzuführen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der berechnete Mindest-SoC ist immer nur ein unterer Grenzwert. Die Batterie kann durch Ladevorgänge natürlich jederzeit einen höheren als den im Reading &#039;&#039;&#039;Battery_OptimumTargetSoC_XX&#039;&#039;&#039; dargestellten optimalen SoC haben. Der optimale SoC sollte nicht unterschritten werden um die oben genannten Zusammenhänge abbilden zu können.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
🎯 &#039;&#039;&#039;Kurzfazit: Was beschreibt Battery_OptimumTargetSoC_XX?&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Battery_OptimumTargetSoC_XX definiert den optimalen Ziel‑SoC, den die Batterie erreichen bzw. nicht unterschreiten sollte, um prognostizierte PV‑Überschüsse aufzunehmen, ausreichende Energiereserven bereitzuhalten und die erforderlichen Pflegezyklen sicherzustellen. Der Wert bezieht sich dabei nicht auf die physikalischen Eigenschaften der Batteriezellen, sondern ergibt sich ausschließlich aus den Steuerungszielen des Moduls – basierend auf den eingestellten Parametern und den prognostizierten Umweltfaktoren. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
===== Die dynamische SOC Steuerung mit Umsetzungsbeispiel =====&lt;br /&gt;
Das Modul bietet eine Unterstützung zur automatisierten Einstellung eines optimalen SoC Wertes.&lt;br /&gt;
&lt;br /&gt;
Ziel ist es, den Minimum SoC in Abhängigkeit der zu erwartenden Solarerträge des aktuellen und des folgenden Tages so einzustellen, dass der prognostizierte Solarertrag von der Batterie aufgenommen werden kann. Die Einspeisung in das öffentliche Netz soll minimiert werden.&lt;br /&gt;
&lt;br /&gt;
Weiterhin soll ein unterer SoC nicht unterschritten, sowie ein oberer Minimum SoC im Normalfall nicht überschritten werden. Der obere Grenzwert stellt sicher, dass die Batterie mindestens bis zu diesem Wert wieder entladen werden kann. Dadurch bleibt innerhalb der Batterie immer genügend Kapazität verfügbar um unvorhergesehene PV Energie aufnehmen zu können.&lt;br /&gt;
&lt;br /&gt;
Aktiviert wird die Unterstützung der Batteriesteuerung durch das Setzen des Attributes &#039;&#039;&#039;ctrlBatSocManagementXX&#039;&#039;&#039; z.B. mit diesen Angaben:&lt;br /&gt;
&lt;br /&gt;
 ctrlBatSocManagementXX lowSoc=x upSoC=x maxSoC=x careCycle=x &lt;br /&gt;
&lt;br /&gt;
so zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 ctrlBatSocManagement01 lowSoc=10 upSoC=50 maxSoC=98 careCycle=20&lt;br /&gt;
&lt;br /&gt;
Dabei steht &#039;XX&#039; für die Nummer der Batterie, welche mit dem Attribut setupBatteryDevXX korrespondiert. &lt;br /&gt;
Ist dieses Attribut gesetzt, werden Steuerungs-Readings erstellt, die der Nutzer auswerten und seine Batterieanlage z.B. via notify oder DOIF steuern kann. &amp;lt;bR&amp;gt;&lt;br /&gt;
Das Reading &#039;&#039;&#039;Battery_OptimumTargetSoC_XX&#039;&#039;&#039; enthält den vom Modul berechneten optimalen Mindest-SoC.&lt;br /&gt;
Das Reading &#039;&#039;&#039;Battery_ChargeRequest_XX&#039;&#039;&#039; wird auf &#039;1&#039; gesetzt, wenn der aktuelle SOC unter den optimalen SOC bzw. minimalen SOC gefallen ist.&lt;br /&gt;
&lt;br /&gt;
Die Schlüssel &#039;&#039;&#039;lowSoc&#039;&#039;&#039; und &#039;&#039;&#039;upSoC&#039;&#039;&#039; sind die unteren und oberen Grenzen, zwischen denen sich der Minimum SoC im normalen Betrieb bewegen soll.&lt;br /&gt;
Der Schlüssel &#039;&#039;&#039;maxSoC&#039;&#039;&#039; stellt eine Ladungsgrenze dar, die mindestens alle X (careCycle) Tage erreicht werden soll. Zu diesem Zweck errechnet das Modul die Anzahl der nötigen Erhöhungen der Minimum Batterieladung von 5% pro Tag um ausgehend vom aktuellen SoC-Level. Der resultierende Minimum SoC Wert wird entsprechend angepasst. Wurde der einstellte maxSoC Level erreicht, startet der Wartungszyklus (careCycle) erneut. &amp;lt;br&amp;gt;&lt;br /&gt;
Der maxSoC in Verbindung mit dem durch &#039;&#039;&#039;careCycle&#039;&#039;&#039; definierten Zyklus soll sicherstellen, dass der Batterieverbund in regelmäßigen Abständen einen Ladungsausgleich vollziehen kann. &lt;br /&gt;
&lt;br /&gt;
Durch die Modullogik erfolgt eine 5 protentige Anhebung des Minimum SoC wenn am Vortag maxSoC nicht erreicht wurde. Die Anhebung erfolgt aber nicht über upSoC. upSoC ist die obere Grenze des Minimum SoC. Wird am Vortag mindestens die maxSoC Ladung erreicht, verringert sich der Minimum SoC wieder schrittweise um 5%, aber nicht tiefer als lowSoc.&lt;br /&gt;
&lt;br /&gt;
Ergänzt wird die Logik noch um die PV Vorhersage. Dabei wird die obige Minimum SoC Berechnung um die erwartete PV Erzeugung des aktuellen und folgenden Tages korrigiert. Das bedeutet, dass der Minimum SoC z.B. von heute 50% auf 10% abgesenkt und dadurch die gespeicherte Energie dem Haushalt zugeführt wird, wenn am heutigen oder kommenden Tag eine entsprechende PV Energie zu erwarten ist um die Batterie wieder vollständig zu laden.&lt;br /&gt;
Dadurch ist immer genügend &amp;quot;Freiplatz&amp;quot; in der Batterie und andererseits hat die Batterie in langen Dunkelphasen eine Reserve für einen eventuellen Stromausfall (falls der abgesichert werden soll) und wird vor einem dauerhaften tiefen SoC geschützt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
===== Umsetzungsbeispiel =====&lt;br /&gt;
&lt;br /&gt;
Wie das Reading &#039;&#039;&#039;Battery_OptimumTargetSoC_XX&#039;&#039;&#039; genutzt werden kann, wird am Beispiel einer Victron Batterieanlage gezeigt. Die Anlage wird durch Cerbo GX Gerät gesteuert. Der Cerbo GX ist per MQTT2 in FHEM eingebunden. Umgesetzt ist die Steuerung der Batterie &#039;01&#039;, d.h. die Angabe &#039;XX&#039; ist durch &#039;01&#039; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die folgende kleine Logik ist in einem &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039; File eingebaut und wird regelmäßig mit&lt;br /&gt;
&lt;br /&gt;
 batSocChargeMgmnt (&#039;&amp;lt;Name SolarForecast Device&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
aufgerufen. Der Aufruf erfolgt durch Angabe der Routine im Attribut &#039;&#039;&#039;ctrlUserExitFn&#039;&#039;&#039; des SolarForecast Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{  &lt;br /&gt;
  # Hinweis: die Zeichen &#039;::&#039; vor der Routine sind durch das SolarForecast Package bedingt&lt;br /&gt;
  ::batSocChargeMgmnt ($name);&lt;br /&gt;
  return;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Routine wird dadurch automatisch am Ende jedes Zyklus (siehe Attribut plantControl-&amp;gt;cycleInterval) ausgeführt.&lt;br /&gt;
Um die SOC Managementfunktion nach Bedarf ein- bzw. ausschalten zu können wird zunächst im SolarForecast Device ein userattr zur Steuerung der SOC-Logik angelegt:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;Device&amp;gt; userattr userFn_BatterySoCManagement:ein,aus&lt;br /&gt;
&lt;br /&gt;
Die Perl Routine &#039;&#039;&#039;batSocChargeMgmnt&#039;&#039;&#039; ist wie folgt aufgebaut:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
###############################################################################&lt;br /&gt;
#&lt;br /&gt;
# Save this file as 99_mySolarForecastUtils.pm, and create your own functions&lt;br /&gt;
# in the new file. They are then available in every Perl expression.&lt;br /&gt;
#&lt;br /&gt;
###############################################################################&lt;br /&gt;
 package main;&lt;br /&gt;
 use strict;&lt;br /&gt;
 use warnings;&lt;br /&gt;
&lt;br /&gt;
 sub&lt;br /&gt;
 mySolarForecastUtils_Initialize($$)&lt;br /&gt;
 {&lt;br /&gt;
   my ($hash) = @_;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
# ab hier eigenen Code eintragen&lt;br /&gt;
###############################################################################&lt;br /&gt;
&lt;br /&gt;
############################################################################&lt;br /&gt;
#      Batterie SOC und Max. Ladestrom Management&lt;br /&gt;
############################################################################&lt;br /&gt;
sub batSocChargeMgmnt {&lt;br /&gt;
  my $name = shift;&lt;br /&gt;
  my $bn   = &#039;01&#039;;                                                                      # Batterienummer (evtl. im Aufruf mitgeben)&lt;br /&gt;
  my $hash = $defs{$name};&lt;br /&gt;
  &lt;br /&gt;
  my $vebus   = &#039;MQTT2_cerboGX_c0619ab34e08_vebus&#039;;                                     # Victron Vebus Device&lt;br /&gt;
  my $vicsets = &#039;MQTT2_cerboGX_c0619ab34e08_settings&#039;;                                  # Victron Einstellungen&lt;br /&gt;
&lt;br /&gt;
  my $maxcspc = 105;                                                                    # max. Ladestrom (A) für Victron MPII Verbund&lt;br /&gt;
  my $preduce = FHEM::SolarForecast::BatteryVal ($name, $bn, &#039;bpinreduced&#039;, $maxcspc);  # reduzierte Ladeleistung aus Bat-Konfig (W)&lt;br /&gt;
  my $actmcc  = ReadingsNum ($vicsets, &#039;MaxChargeCurrent&#039;, undef);                      # akt. Ladestromeinstellung&lt;br /&gt;
  my $load    = $actmcc // $maxcspc;                                                    # Soll-Ladestrom (A)  &lt;br /&gt;
&lt;br /&gt;
  ## Battery SoC Management&lt;br /&gt;
  ###########################&lt;br /&gt;
  my $ubsm = AttrVal ($name, &#039;userFn_BatterySoCManagement&#039;, &#039;aus&#039;); &lt;br /&gt;
  &lt;br /&gt;
  if ($ubsm eq &#039;ein&#039;) { &lt;br /&gt;
    my $bcrq = ReadingsNum ($name,    &#039;Battery_ChargeRequest_&#039;.$bn,     0);&lt;br /&gt;
    my $csoc = ReadingsNum ($vicsets, &#039;MinimumSocLimit&#039;,               10);             # akt. SoC&lt;br /&gt;
    my $osoc = ReadingsNum ($name,    &#039;Battery_OptimumTargetSoC_&#039;.$bn, 10);             # Soll-SoC&lt;br /&gt;
	my $surp = ReadingsNum ($name,    &#039;Current_Surplus&#039;,                0);             # aktueller PV-Überschuß&lt;br /&gt;
	&lt;br /&gt;
    if ($csoc != $osoc) {&lt;br /&gt;
      CommandSet (undef, &amp;quot;$vicsets MinimumSocLimit $osoc&amp;quot;);&lt;br /&gt;
      Log3 ($name, 3, qq{$name - userFn SoCMgmnt -&amp;gt; MinimumSocLimit in $vicsets set to $osoc %});&lt;br /&gt;
    }&lt;br /&gt;
	                                           &lt;br /&gt;
    if ($bcrq &amp;amp;&amp;amp; $surp &amp;lt; 1000) {                                                       # max. Ladestrom (A) b. Battery_ChargeRequest&lt;br /&gt;
      $load = $preduce / 48;                                                           # bei 48V Batteriesystem&lt;br /&gt;
    }&lt;br /&gt;
	else {&lt;br /&gt;
	  $load = $maxcspc;&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  ## Einstellung MPII Verbund MaxChargeCurrent&lt;br /&gt;
  ##############################################&lt;br /&gt;
  if ($actmcc &amp;amp;&amp;amp; $load != $actmcc) {&lt;br /&gt;
    CommandSet (undef, &amp;quot;$vicsets MaxChargeCurrent $load&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
    Log3 ($name, 3, qq{$name - userFn ChargeMgmnt -&amp;gt; MaxChargeCurrent in $vicsets set }.&lt;br /&gt;
                    qq{from old $actmcc A to $load A});&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  readingsSingleUpdate ($hash, &#039;userFn_MPII_MaxChargeCurrent_set&#039;, $load, 0);&lt;br /&gt;
  &lt;br /&gt;
return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
###############################################################################&lt;br /&gt;
# Ende eigener Code&lt;br /&gt;
&lt;br /&gt;
1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ist im SolarForecast Device das Reading  &#039;&#039;&#039;Battery_ChargeRequest_01&#039;&#039;&#039; gesetzt, ist der aktuelle SOC kleiner als der optimale SOC und die Batterie wird (eventuell aus dem öffentlichen Netz) geladen. Das kann automatisch durch den Cerbo GX bzw. in anderen Anlagen durch einen entsprechenden Befehl erfolgen.&lt;br /&gt;
Damit die Netzbeladung nicht mit der vollen Ladestromstärke geschieht, wird der Ladestrom auf den gewünschten Wert (hier 21 A -&amp;gt; ca. 1000 W bei einem 48V System) reduziert sofern kein oder zu wenig PV-Überschuß vorhanden ist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== weitere mögliche Aspekte der SOC- und Batterieladesteuerung ====&lt;br /&gt;
&lt;br /&gt;
SolarForecast liefert durch seine internen Logiken bereits sehr hilfreiche Signale zur Steuerung von Batteriesystemen in Form von Readings an. Abhängig von den individuellen Möglichkeiten der vorhandenen Anlage käme zum Beispiel zusätzlich zu einer Steurung des optimalen SOC oder der Zeitfenster für die Batterieaufladung auch eine Steuerung des Ladestroms bzw. der verwendeten Ladeleistung in Betracht.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hintergründe:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Das Laden eines Akkus mit möglichst gleichbleibender und geringer Leistung wirkt sich positiv auf dessen Langlebigkeit aus, was u.a. auch daran liegt, dass der Temperaturstreß im Akku bei langsamer Energiezuführung nur gering ist.&lt;br /&gt;
&lt;br /&gt;
* Ein geringer Ladestrom führt zu einem geringen Absacken der Akkuspannung beim (ggf, temporären) Abschalten des Ladestroms, was sich positiv auf die SOC-Schätzung auswirkt.&lt;br /&gt;
    &lt;br /&gt;
* Ein geringer Ladestrom führt, insb. bei Nutzung passiver Balancer (sind in den Akku-Systemen üblicherweise verbaut), zu einer geringen Differenz zwischen den einzelnen Zellspannungen und damit zu einer besseren Kapazitätsausnutzung eins Akkus.&lt;br /&gt;
&lt;br /&gt;
* Ein geringer Ladestrom kann zu einem zeitlich punktgenauen Zielfüllstand (im Winter 100%, ansonsten natürlich weniger) am Ende des Tages führen.&lt;br /&gt;
    &lt;br /&gt;
* Eine geringer Ladestrom führt auch zu geringen Leitungsverlusten, da der Strom quadratisch zu den Leitungsverlusten beiträgt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Weiterhin kann auch die Verweildauer oder die Begrenzung des SOC, auf den die Batterie maximal geladen werden soll, Gegenstand von Optimierungen sein.&lt;br /&gt;
&lt;br /&gt;
Die häufig zu findende Empfehlung, Akkus nicht zu lange bei einem SOC von 100% verweilen zu lassen, liegt weniger an dem SOC als solchem, sondern daran, dass &#039;&#039;SOC=100%&#039;&#039; üblicherweise dadurch ermittelt wird, dass eine Zelle im Akku einen Spannungsschwellenwert überschreitet, der – würde dieser Schwellenwert zeitlich länger überschritten sein – zu einer Schädigung des Akkus führen könnte. Schädlich sind insbesondere häufige Nachladevorgänge bei Werten um die 100% SOC, da Zellen dann ja häufiger und damit - integral gesehen - auch länger den o.g. Schwellenwert überschreiten.&lt;br /&gt;
&lt;br /&gt;
Einige Akku-Hersteller, z.B. BYD, haben auf o.g, Grund in der (neueren) Firmware Ihrer Systeme einen SOC-Threshold (bei BYD liegt dieser bei 95%) eingebaut. Dieser Wert muss nach einem erreichten SOC von 100% unterschritten  werden, bevor überhaupt eine weitere Ladung erfolgt. Insbesondere in der dunklen Jahreszeit kann es daher sinnvoll sein, den Akku unter Verwendung von PV-Leistung so zu füllen, dass dieser möglichst nur einmal vor Einbruch der Dunkelheit auf &#039;&#039;SOC=100%&#039;&#039; geladen wird. Hierbei sollte darauf geachtet werden, dass der Ladeschlussstrom des jeweiligen Systems nicht unterschritten wird. &lt;br /&gt;
&lt;br /&gt;
SolarForecast unterstützt die oben betrachtete Batteriesteuerung durch die optionale Angabe von &#039;&#039;&#039;loadAbort&#039;&#039;&#039; im Attribut &#039;&#039;&#039;ctrlBatSocManagementXX&#039;&#039;&#039;. Das in diesem Kontext erstellte Reading &#039;&#039;&#039;Battery_ChargeAbort_XX&#039;&#039;&#039; stellt die auswertbaren Steuerungsinformationen zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== PV-Prognose und Verbrauch optimierte Beladungssteuerung unter Berücksichtigung einer Wirkleistungsbegrenzung ====&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2025-04-25 143910.png|right|thumb|400px|Batterie Popup &amp;quot;nur laden wenn Einspeiselimit überschritten&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
Die in diesem Abschnitt beschriebene Ladestrategie &#039;&#039;&#039;loadRelease&#039;&#039;&#039; wird im Modul als &#039;&#039;&#039;Ladefreigabe&#039;&#039;&#039; bezeichnet.&lt;br /&gt;
&lt;br /&gt;
Üblicherweise wird die Batterie geladen. sobald PV-Überschuß vorhanden ist ohne eine Prognose zu berücksichtigen. Dadurch sind die Batterien im Sommer unter Umständen schon um 10-12 Uhr voll geladen und die Anlage liefert ihre mehr oder weniger volle Energie (je nach Ausrichtung) in das öffentliche Netz. Dann könnte es zu einer Begrenzung der PV-Leistung durch einen Schwellenwert (z.B. 70%-Regelung) oder eventuell Zwangsabregelung durch den Netzbetreiber kommen.&lt;br /&gt;
&lt;br /&gt;
Hintergrund dieser Erweiterung ist das Bestreben, eine optimale Unterstützung bei der Maximierung des Eigenverbrauchs zu geben und einen Beitrag zur Netzstabilität zu leisten.&lt;br /&gt;
Das Ziel der Beladungssteuerung der Batterie ist es, die Ladung der Batterie über den Tag verteilt so zu steuern, dass die Batterie erst dann geladen wird, wenn durch den PV-Überschuß eine Netzeinspeisung erfolgen würde bzw. ein Grenzwert erreicht werden würde, der zu einer Abregelung der PV-Anlage führen könnte.&lt;br /&gt;
Es kann auch zu einer Zwangsabregelung durch den Netzbetreiber führen, was vermieden werden soll.&lt;br /&gt;
 &lt;br /&gt;
Die interne Kalkulationslogik erstellt zu diesem Zweck ein Reading &#039;&#039;&#039;Battery_ChargeUnrestricted_XX&#039;&#039;&#039;.&lt;br /&gt;
Dieses Reading gibt dem User ein Signal, ob zu der aktuellen Stunde der Ladevorgang der Batterie freigegeben (1) oder nicht freigegeben werden sollte (0). Die Freigabe zur Ladung bedeutet dass:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Battery_ChargeUnrestricted_XX=1&#039;&#039;&#039; die Batterie mit ihrer vollen, oder der im Reading [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#leistungsoptimierte_Beladungssteuerung_mit_dem_Fokus_geringe_Verlustleistung_und_Verschleiß|Battery_ChargeOptTargetPower_XX]] angegebenen Ladeleistung angesteuert werden sollte um wie prognostiziert am Ende des Sonnentages die volle bzw. maximal mögliche Ladung zu erhalten..&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Battery_ChargeUnrestricted_XX=0&#039;&#039;&#039; die Batterie nur geladen werden sollte wenn der im Attribut plantControl-&amp;gt;feedinPowerLimit definierte Wert überschritten wird&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
Ist keine Freigabe zur Ladung vorhanden, kann bzw. sollte dennoch eine Ladung der Batterie vorgenommen werden, sofern eine über dem im &amp;lt;br&amp;gt;&lt;br /&gt;
Attribut &#039;&#039;&#039;plantControl-&amp;gt;feedinPowerLimit&#039;&#039;&#039; definierten Limit liegende Einspeiseleistung vorhanden ist. In diesem Status sollte die Batterie nur mit der Differenzleistung von vorhandener Einspeiseleistung und dem gesetzen Einspeiselimit geladen werden und damit das gesetzte Einspeiselimit einhalten ohne die Anlage abzuregeln. Ist die Batterie in einer Balkengrafikebene dargestellt, wird im Mouse-Over Popup die Battrie mit &#039;&#039;&amp;quot;nur laden wenn Einspeiselimit überschritten&amp;quot;&#039;&#039; gekennzeichnet.&lt;br /&gt;
&lt;br /&gt;
Die Möglichkeiten der Batteriesteuerung sind stark von der individuellen Anlage abhängig und können hier nicht beschrieben werden. Ein Umsetzungsbeispiel mit einer Victron-Anlage mit Pylontech Batterie ist weiter unten dargestellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
===== Aktivierung und Arbeitsweise =====&lt;br /&gt;
&lt;br /&gt;
Die implementierte Logik zur optimierten Batterie Beladungssteuerung wird aktiviert, wenn folgende Kriterien erfüllt sind: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* der Schlüssel &#039;&#039;&#039;capacity&#039;&#039;&#039; in den setupInverterDevXX Atributen ist gesetzt&lt;br /&gt;
* das Attribut &#039;&#039;&#039;ctrlBatSocManagementXX&#039;&#039;&#039; für die jeweilige Batterie ist gesetzt&lt;br /&gt;
* der Schlüssel &#039;&#039;&#039;cap&#039;&#039;&#039; im Attribut setupBatteryDevXX der jeweiligen Batterie ist gesetzt&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Die Logik arbeitet wie folgt:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der resultierende Schwellenwert der Wirkleistungsbegrenzung: der Gesamtanlage wird durch die Auswertung der in den Inverter-Attributen setupInverterDevXX  gesetzen Schlüssel limit (optional) und capacity ermittelt. Inverter mit gesetztem Schlüssel feed = grid (deren Energie wird ausschließlich in das öffentlich Netz eingespeist) werden von der Betrachtung in diesem Kontext ausgeschlossen.&lt;br /&gt;
&lt;br /&gt;
;Die benötigte Beladung bis zu maxSoC (im Attribut setupBatteryDevXX) : wird ermittelt und mit der zu erwartenden PV Tagesprognose in Beziehung gesetzt. Sofern die PV-Erzeugung abzgl. Verbrauch noch nicht das Wirkleistungbegrenzungs-Limit erreicht UND noch genügend PV-Überschuß für eine Ladung auf &#039;&#039;maxSoC&#039;&#039; im Laufe der kommenden Stunden des Tages zu erwarten ist, bleibt das Reading &#039;&#039;&#039;Battery_ChargeUnrestricted_XX = 0&#039;&#039;&#039;. Die erreichte Qualität der Steuerungslogik ist stark von der Prognosequaliät abhängig. Um die Steuerung resilienter zu gestalten, wird per default ein Sicherheitsaufschlag von 50% auf die prognostizierte benötigte Ladeenenergie auf Stundenbasis einkalkuliert. Dieser Wert kann mit dem Attribut &#039;&#039;&#039;ctrlBatSocManagementXX-&amp;gt;safetyMargin&#039;&#039;&#039; individuell angepasst werden.&lt;br /&gt;
&lt;br /&gt;
;Wird das Wirkleistungbegrenzungs-Limit erreicht/überschritten und/oder die PV-Überschußprognose: zzgl. eines Sicherheitspuffers unterschritten, wird &#039;&#039;&#039;Battery_ChargeUnrestricted_XX = 1&#039;&#039;&#039; gesetzt. Der User kann darauf reagieren und den Batterie Ladevorgang aktivieren. Die Möglichkeiten der Aktivierung sind natürlich von der installierten Anlage abhängig. Das SolarForecast Device greift nicht in die Batteriesteuerung direkt ein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Anders ausgedrückt erfolgt immer dann eine Ladefreigabe, wenn einer der nachfolgenden Sachverhalte &#039;&#039;wahr&#039;&#039; ist:&lt;br /&gt;
&lt;br /&gt;
- die benötigte Ladeenergie (aller installierten Batterien) &amp;gt;= PV-Restüberschuß des Tages (Reading RestOfDayPVforecast) zzgl. Sicherheitsaufschlag&lt;br /&gt;
&lt;br /&gt;
ODER&lt;br /&gt;
&lt;br /&gt;
- der Zeitpunkt des PV-Erzeugungszenit des laufenden Tages überschritten ist (Reading Today_MaxPVforecastTime)&lt;br /&gt;
&lt;br /&gt;
ODER&lt;br /&gt;
&lt;br /&gt;
- wenn die aktuelle PV Leistung &amp;gt;= einer eventuellen Wechselrichter-Leistungsbegrenzung ist (Summe aller WR-Begrenzungen)&lt;br /&gt;
&lt;br /&gt;
ODER&lt;br /&gt;
&lt;br /&gt;
- wenn das BatSoc-Management _nicht_ aktiviert ist (nicht alle oben genannten Aktivierungskriterien erfüllt sind)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sind mehrere Batterien installiert und durch das Management einer Batterie die Einhaltung der genannten Kriterien bzw. Sachverhalte erwirkt wird, bleiben die weiteren Batterien im Modus Ladefreigabe (Battery_ChargeUnrestricted_XX=1).  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Umsetzungsbeispiel Batterie Ladesteuerung mit Victron GX Venus über den Grid Setpoint =====&lt;br /&gt;
&lt;br /&gt;
Ziel der Steuerung ist es abhängig vom Wert des Readings Battery_ChargeUnrestricted_XX (z.B. Battery_ChargeUnrestricted_01) die Ladung des angeschlossenen Batteriesystems zu aktivieren bzw. zu deaktivieren.&lt;br /&gt;
Das vorliegende Beispiel soll umzusetzen:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Battery_ChargeUnrestricted_01 = 0 -&amp;gt; Batterie nicht aufladen bzw. nur laden wenn Einspeiselimit überschritten (Attribut plantControl-&amp;gt;feedinPowerLimit)&lt;br /&gt;
* Battery_ChargeUnrestricted_01 = 1 -&amp;gt; Batterie aufladen&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der Grid Setpoint ist ein Parameter in den Victron Systemeinstellungen. Das Victron System wird den eingestellten Grid Setpoint versuchen einzuhalten und bei einem positiven Wert Energie aus dem Netz beziehen bzw. bei einem negativen Grid Setpoint Energie in das Netz einspeisen.&lt;br /&gt;
&lt;br /&gt;
Normalerweise wird das Victron System die erzeugte PV Energie zunächst zur Deckung des Hausverbrauchs verwenden, ist dann noch ein PV Überschuß vorhanden, die Batterien aufladen und bei weiter vohandenen PV Überschuß diese Energie in das öffentliche Netz einspeisen sofern dem System eine Einspeisung erlaubt ist. Anderenfalls werden die Wechselrichter oder MPPT Smartloader heruntergeregelt bzw. limitiert. &lt;br /&gt;
&lt;br /&gt;
In der Standardeinstellung ist beim Victron System ein Grid Setpoint von ca. 20 bis 50 Watt, d.h. das System strebt danach diese Vorgabe zu erfüllen zieht ständig Energie in diesem Bereich aus dem öffentlich Netz von einem gelegentlichen Überschwingen der Regelung abgesehen. Damit ein eventueller PV Überschuß nicht zum Laden der Batterie verwendet, sondern statt dessen in das öffentliche Netz eingespeist wird, muß der Grid Setpoint um diesen Betrag abgesenkt werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2025-02-24 114403.png|right|thumb|400px|Integration des Grid Setpoint-Managements in den Own_Spec-Bereich]]&lt;br /&gt;
&lt;br /&gt;
Damit man später per Attribut bzw. über den [[#Formatierung_der_Inhalte_im_Bereich_&amp;quot;Graphic_Header_Own_Specification&amp;quot;|Own_Spec-Bereich]] die automatische Ladesteuerung über den Grid Setpoint ein- bzw. ausschalten kann, legen wir ein userattr an:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 userattr &amp;lt;Name&amp;gt; userFn_GridSetpointManagement:ein,aus&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Weiterhin sind einige Vorbereitungen im Device MQTT2_cerboGX_c0619ab34e08_settings vorzunehmen. Dieses Device ist im vorliegenden Beispiel ein in FHEM vorhandenes MQTT2_DEVICE, über das die Victron CerboGX Einstellungen zugreifbar sowie einstellbar sind. Die Vorgehensweise zur Erstellung des MQTT2_DEVICE ist hier nicht beschrieben und wird vorausgesetzt.&lt;br /&gt;
&lt;br /&gt;
Damit ein entsprechender Set-Befehl zur Einstellung des Grid Setpoints vorhanden ist, werden folgende Attribute gesetzt:&lt;br /&gt;
&lt;br /&gt;
 attr MQTT2_cerboGX_c0619ab34e08_settings jsonMap Settings_CGwacs_AcPowerSetPoint_value:GridSetpoint&lt;br /&gt;
 attr MQTT2_cerboGX_c0619ab34e08_settings setList GridSetpoint W/c0619ab34e08/settings/0/Settings/CGwacs/AcPowerSetPoint {&amp;quot;value&amp;quot;:$EVTPART1}&lt;br /&gt;
&lt;br /&gt;
Nach dieser Attributierung kann mit einem &amp;quot;&#039;&#039;set MQTT2_cerboGX_c0619ab34e08_settings GridSetpoint &amp;lt;Wert&amp;gt;&#039;&#039;&amp;quot; der Grid Setpoint eingestellt werden.&lt;br /&gt;
&lt;br /&gt;
Das Attribut userFn_GridSetpointManagement kann nun im Perl Code ausgewertet werden um das Grid Setpoint-Management ein- bzw. auszuschalten.&lt;br /&gt;
Der nachfolgende Code wird in die Datei &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039; eingefügt. Ist diese Datei nicht vorhanden, legen wir sie vorab als Kopie der ausgelieferten 99_myUtils.pm an.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible mw-collapsed&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Code Management Batterieladung über Victron Grid Setpoint -&amp;gt;&#039;&#039;&#039; &amp;lt;div class=&amp;quot;mw-collapsible-content&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
###############################################################################&lt;br /&gt;
#&lt;br /&gt;
# Save this file as 99_mySolarForecastUtils.pm, and create your own functions&lt;br /&gt;
# in the new file. They are then available in every Perl expression.&lt;br /&gt;
#&lt;br /&gt;
###############################################################################&lt;br /&gt;
 package main;&lt;br /&gt;
 use strict;&lt;br /&gt;
 use warnings;&lt;br /&gt;
&lt;br /&gt;
 sub&lt;br /&gt;
 mySolarForecastUtils_Initialize($$)&lt;br /&gt;
 {&lt;br /&gt;
   my ($hash) = @_;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
# ab hier eigenen Code eintragen&lt;br /&gt;
###############################################################################&lt;br /&gt;
&lt;br /&gt;
############################################################################&lt;br /&gt;
#   Steuerung Start/Stop der Batterieladung über den Victron Grid Setpoint&lt;br /&gt;
############################################################################&lt;br /&gt;
sub gridSetpointMgmt {&lt;br /&gt;
  my $name = shift;&lt;br /&gt;
  my $hash = $defs{$name};&lt;br /&gt;
  &lt;br /&gt;
  my $vicsets   = &#039;MQTT2_cerboGX_c0619ab34e08_settings&#039;;                               # Device Victron Einstellungen&lt;br /&gt;
  my $gspdef    = 20;                                                                  # Default Einstellung des Grid Setpoint&lt;br /&gt;
  my $targetgsp = $gspdef;                                                             # Voreinstellung Grid Setpoint&lt;br /&gt;
  my $neggspmax = FHEM::SolarForecast::CurrentVal ($name, &#039;feedinPowerLimit&#039;, 5000);   # max. gewünschte Einspeiseleistung in Watt&lt;br /&gt;
  $neggspmax    = $neggspmax * -1;&lt;br /&gt;
  my $gspm      = AttrVal ($name, &#039;userFn_GridSetpointManagement&#039;, &#039;aus&#039;);             # Freischaltung des Grid Setpoint-Managements&lt;br /&gt;
  my $curgsp    = ReadingsNum ($vicsets, &#039;GridSetpoint&#039;,         $gspdef);             # aktuelle Einstellung Grid Setpoint&lt;br /&gt;
  &lt;br /&gt;
  if ($gspm eq &#039;ein&#039;) { &lt;br /&gt;
    my $bcrq = ReadingsNum ($name, &#039;Battery_ChargeUnrestricted_01&#039;, 0);         # Ladefreigabe (1 -&amp;gt; Bat Ladefreigabe)&lt;br /&gt;
    my $surp = ReadingsNum ($name, &#039;Current_Surplus&#039;,               0);         # aktueller PV-Überschuß&lt;br /&gt;
	&lt;br /&gt;
    if (!$bcrq) {                                                               # Grid Setpoint absenken wenn keine .. &lt;br /&gt;
        $targetgsp = $gspdef - $surp;                                           # ..Batterie Ladefreigabe&lt;br /&gt;
        $targetgsp = $neggspmax if($targetgsp &amp;lt; $neggspmax);                    # Begrenzung der Einspeiseleistung&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  if ($curgsp != $targetgsp) {&lt;br /&gt;
	  fhem (&amp;quot;set $vicsets GridSetpoint $targetgsp&amp;quot;);&lt;br /&gt;
      Log3 ($name, 3, qq{$name - userFn gridSetpointMgmt -&amp;gt; GridSetpoint in $vicsets set to $targetgsp});&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  readingsSingleUpdate ($hash, &#039;userFn_Victron_GridSetpoint_set&#039;, $targetgsp, 0);&lt;br /&gt;
  &lt;br /&gt;
return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
###############################################################################&lt;br /&gt;
# Ende eigener Code&lt;br /&gt;
&lt;br /&gt;
1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der Vergleich des Setpoints mit der Vorgabe von &#039;&#039;$neggspmax&#039;&#039; dient dazu die maximale Einspeiseleistung in das öffentliche Netz zu begrenzen. Ist diese Grenze erreicht, wird der noch verbleibende Überschuß in die Batterie geladen. Dadurch wird eine Abregelung der Anlage vermieden wenn der Schwellenwert &#039;&#039;$neggspmax&#039;&#039;erreicht ist sofern die Batterie aufnahmefähig ist und nicht voll geladen ist. &lt;br /&gt;
&lt;br /&gt;
Damit die Routine mit jedem Zyklus im Modul ausgeführt wird, legen wir sie im Attribut &#039;&#039;&#039;ctrlUserExitFn&#039;&#039;&#039; an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr &amp;lt;Name&amp;gt; ctrlUserExitFn  {  &lt;br /&gt;
                               ::gridSetpointMgmt  ($name);&lt;br /&gt;
                            }&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zum Management des automatischen Grid Setpoint und der Anzeige des eingestellten Wertes wird das Attribut und die Readinganzeige in den Own_Spec-Bereich eingebunden, z.B.:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; graphicHeaderOwnspec  #Settings&lt;br /&gt;
                                   SetPoint&amp;amp;nbsp;Management:userFn_GridSetpointManagement&lt;br /&gt;
                                   Grid&amp;amp;nbsp;Setpoint:GridSetpoint@MQTT2_cerboGX_c0619ab34e08_settings&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== leistungsoptimierte Beladungssteuerung mit dem Fokus geringe Verlustleistung und Verschleiß ====&lt;br /&gt;
&lt;br /&gt;
Über das Attribut ctrlBatSocManagementXX kann mit dem Schlüssel loadStrategy die Ladestrategie &#039;&#039;&#039;optPower&#039;&#039;&#039; oder &#039;&#039;&#039;smartPower&#039;&#039;&#039; eingestellt werden.&lt;br /&gt;
Das SF-Modul bietet ein weiteres Reading &#039;&#039;&#039;Battery_ChargeOptTargetPower_XX&#039;&#039;&#039; zur Batteriesteuerung an. Dieses Reading liefert eine kalkulierte optimale Ladeleistung in Watt.&lt;br /&gt;
&lt;br /&gt;
Die in diesem Abschnitt beschriebene Ladestrategie &#039;&#039;&#039;optPower&#039;&#039;&#039; wird im Modul als &#039;&#039;&#039;optimierte Ladeleistung&#039;&#039;&#039;, die Ladestrategie &#039;&#039;&#039;smartPower&#039;&#039;&#039; als &#039;&#039;&#039;zieloptimierte Ladeleistung&#039;&#039;&#039; bezeichnet.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Beide Strategien kalkulieren die Ladeleistung kontinuierlich neu und berücksichtigen dabei:&lt;br /&gt;
&lt;br /&gt;
* die Prognose der PV-Erzeugung der nächsten Stunden und des (Rest-)Tages&lt;br /&gt;
* den prognostizierten Verbrauch auf Stunden- bzw. Tagesbasis&lt;br /&gt;
* eine eventuell mögliche Überschreitung des gesetzten Einspeiselimits (plantControl-&amp;gt;feedinPowerLimit)&lt;br /&gt;
* die gesetzten Leistungsparameter der Batterie &lt;br /&gt;
* das Ziel, am Tagesende einen möglichst maximalen SoC der Batterie erreicht zu haben bzw. den eingestellten Ziel-SoC &#039;&#039;&#039;loadTarget&#039;&#039;&#039;&lt;br /&gt;
* die Effizienz der Batterieanlage (Einstellung &#039;&#039;&#039;setupBatteryDevXX-&amp;gt;efficiency&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der Fokus der implementierten Logik liegt dabei auf einer kontinuierlichen Ladeleistung, die aber unter den oben genannten Gesichtspunkten möglichst (relativ) gering sein soll um den Batterieverschleiß und die Verlustleistung zu minimieren. Die im Reading angezeigte Ladeleistung kann mit geeigneten Mitteln direkt in die Leistungssteuerung der Batterie eingebracht werden. Natürlich kann die Leistung auch vorab in einen optimalen Ladestrom umgerechnet werden.&lt;br /&gt;
&lt;br /&gt;
Da das Ergebnis der Kalkulation stark von den Prognosen abhängt, ist zur Erhöhung der Resilienz per Default ein Sicherheitszuschlag von 20% eingebaut. Dieser Wert kann mit dem Attribut &#039;&#039;&#039;ctrlBatSocManagementXX-&amp;gt;safetyMargin&#039;&#039;&#039; individuell angepasst werden. &lt;br /&gt;
&lt;br /&gt;
Ist kein PV-Überschuß (mehr) vorhanden / prognostiziert oder das Ladeziel erreicht, erfolgt ein Rückfall der Ladeleistung im Reading Battery_ChargeOptTargetPower_XX auf den  im Attribut &#039;&#039;&#039;setupBatteryDevXX-&amp;gt;pinmax&#039;&#039;&#039; angegebenen Wert. Ist dieser Wert nicht gesetzt, erfolgt der Rückfall auf &amp;quot;Unendlich&amp;quot; (9223372036854775807). &lt;br /&gt;
 &lt;br /&gt;
Im Reading Battery_ChargeOptTargetPower_XX wird der Wert des Parameters &#039;&#039;&#039;setupBatteryDevXX-&amp;gt;pinreduced&#039;&#039;&#039; gesetzt, wenn weniger Ladeleistung als pinreduced berechnet wurde (Einhaltung einer Mindestladeleistung) oder wenn der SoC der Batterie &amp;lt;= [[#Aktivierung_des_Batterie_SOC-_und_Lade-Managements|lowSoC]] beträgt.&lt;br /&gt;
Somit wird die Batterie bei einer Anforderungsladung bei Unterschreitung von lowSoC mit nur wenig Leistung aus dem Grid geladen falls es nötig sein sollte.&lt;br /&gt;
Es ist demzufolge ratsam den optionalen Parameter &#039;&#039;&#039;setupBatteryDevXX-&amp;gt;pinreduced&#039;&#039;&#039; zu setzen, da ansonsten ebenfalls ein Rückfall auf &#039;&#039;&#039;setupBatteryDevXX-&amp;gt;pinmax&#039;&#039;&#039; bzw. &amp;quot;Unendlich&amp;quot; erfolgt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Beide Strategien, optPower und smartPower, setzen die zuvor beschriebene Arbeitsweise um.&lt;br /&gt;
Ergänzend wird bei der Ladestrategie &#039;&#039;&#039;smartPower&#039;&#039;&#039; die generelle Erreichbarkeit des Ladeziels bei der Festlegung der Ladeleistung berücksichtigt. Es führt dazu dass:&lt;br /&gt;
&lt;br /&gt;
* die Ladeleistung im Reading Battery_ChargeOptTargetPower_XX auf einen tendenziell höheren Wert als bei der optPower-Strategie gesetzt wird, wenn/solange das eingestellte Ladeziel als unerreichbar kalkuliert wird&lt;br /&gt;
* bei kalkulierter Erreichbarkeit des Ladeziels der Sicherheitsaufschlag linear absenkend proportional zum Kehrwert des verfügbaren PV-Überschusses auf die Ladeleistung angewendet wird&lt;br /&gt;
&lt;br /&gt;
Der nächste Abschnitt erläutert die smartPower Funktionen etwas eingehender.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
===== smartPower - die zieloptimierte Ladeleistung  =====&lt;br /&gt;
Die hinter smartPower liegende Anpassungslogik wird nachfolgend etwas näher beschrieben.&lt;br /&gt;
Ausgangspunkt ist das Ergbnis einer Ratio-Funktion aus dem (Rest)Tages-PV-Überschuß und benötigter Energie zur Erlangung des Batterie Ladeziels.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lineare Interpolation zwischen pinmax und abgesicherter minpower&#039;&#039;&#039;  &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Variablen&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;P&#039;&#039;&#039;: resultierende Leistung.&lt;br /&gt;
* &#039;&#039;&#039;pinmax&#039;&#039;&#039;: maximale Ladeleistung.&lt;br /&gt;
* &#039;&#039;&#039;limpower&#039;&#039;&#039;: Leistungslimit, d.h. Ladeleistungssollwert.&lt;br /&gt;
* &#039;&#039;&#039;r&#039;&#039;&#039;: Verhältnis in Prozent (r = spday·100 / whneed).&lt;br /&gt;
* &#039;&#039;&#039;otpMargin&#039;&#039;&#039;: Prozentwert der Bandbreite, über die die Absenkung linear verläuft (die Steilheit kann mit dem Attributwert ctrlBatSocManagementXX-&amp;gt;safetyMargin im Device eingestellt werden).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Kennlinie der für smartPower eingesetzten Funktion ist stückweise definiert über das Verhältnis Ratio &#039;&#039;𝑟 = spday x 100 / &amp;lt;benötigte Ladeenergie bis Ziel&amp;gt;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
* Für 𝑟 ≤ 100: &#039;&#039;𝑃 = pinmax&#039;&#039;, Interpretation: Es ist viel Bedarf vorhanden bzw. Überschuss ≤ 100 % des Bedarfs → maximal laden.&lt;br /&gt;
* Für 𝑟 ≥ 100 + otpMargin: &#039;&#039;𝑃 = limpower ⋅ (1 + otpMargin / 100 )&#039;&#039;&lt;br /&gt;
* Für 100 &amp;lt; 𝑟 &amp;lt; 100 + otpMargin: lineare Absenkung von &#039;&#039;&#039;P&#039;&#039;&#039; mit zunehmendem &#039;&#039;&#039;r&#039;&#039;&#039; für den Bereich 100 &amp;lt; 𝑟 &amp;lt; 100 + otpMargin. &#039;&#039;&#039;P&#039;&#039;&#039; wird bei 𝑟 = 100 gleich &#039;&#039;&#039;pinmax&#039;&#039;&#039; und bei 𝑟 = 100 + otpMargin gleich &#039;&#039;limpower ⋅ ( 1 + otpMargin/100 )&#039;&#039;, Interpretation: Sobald der Überschuss über den Bedarf hinausgeht (ratio &amp;gt; 100), wird das Ladeleistungslimit schrittweise von pinmax Richtung limpower reduziert; die Reduktion erfolgt gleichmäßig über die Margin-Spanne.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lineare Interpolation und Steigung&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die Differenz &#039;&#039;(pinmax − limpower)&#039;&#039; wird gleichmäßig auf die otpMargin-Prozentpunkte verteilt. Die Steigung der Geraden ist&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
slope = − (pinmax − limpower) / otpMargin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
das heißt die Leistung sinkt um diesen Betrag pro Prozentpunkt von &#039;&#039;&#039;r&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Nach Umformung ist der Zusammenhang wie folgt darstellbar:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
𝑃 = pinmax − ( pinmax − limpower) ⋅ ((𝑟 − 100) / otpMargin)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
und ist äquivalent zu&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
𝑃 = pinmax + ( 𝑟 − 100 ) ⋅ slope&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Numerisches Beispiel&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;limpower&#039;&#039;&#039; = 1000 W, &#039;&#039;&#039;pinmax&#039;&#039;&#039; = 3000 W, &#039;&#039;&#039;otpMargin&#039;&#039;&#039; = 20&lt;br /&gt;
* Unterschied = 2000 W, Steigung = −2000/20 = −100 W/%&lt;br /&gt;
* Für &#039;&#039;&#039;r = 105&#039;&#039;&#039;: 𝑃 = 3000 − 2000 ⋅ ( 5 / 20 ) = 3000 − 500 = 2500 W&lt;br /&gt;
* Für &#039;&#039;&#039;r = 120&#039;&#039;&#039; ergibt die Formel den abgesicherten Endwert 1200 W&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Formel sorgt dafür, dass die Zielleistung stufenlos und vorhersehbar reduziert wird, wenn der relative Rest-Überschuss des Tages über 100% steigt, und erreicht bei Ende der otpMargin den geplanten abgesicherten Wert.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Ratio Kennlinie.png|right|thumb|200px|abfallend proportionale Anpassungsfunktion]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In einem grafischen Diagramm stellt sich die abfallend proportionale Anpassungsfunktion der resultierenden Soll-Ladeleistung wie nebenstehend abgebildet dar. Dabei entspricht pow=100 dem jeweiligen pinmax Wert (hier 3000 W). So ist auch pow=0 mit dem abgesicherten Endwert (hier 1200 W) gleichzusetzen. Die Linie verläuft waagerecht bei pinmax solange das das Ratio  r ≤ 100 % und knickt an r == 100 mit steigenden r nach unten. Es verringert sich pow linear von pinmax zu limpower zzgl. otpMargin.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Durch diese Maßnahmen wird eine flexible Lademöglichkeit bis pinmax erreicht, die sich bei unvorhergesehenen Aufklarungen mit starker Sonneneintrahlung bei ansonsten sehr bedeckten Himmel positiv auswirkt. Andererseits wird die Erhöhung der Ladeleistung weiter begrenzt, wenn viel PV-Überschuß in Verbindung mit einer generellen Erreichbarkeit des Ladeziels zum Ende des Tages prognostiziert ist. Man könnte die Ladestrategie &#039;&#039;&#039;smartPower&#039;&#039;&#039; in ihrer Wirkung als einen Mix aus &#039;&#039;&#039;optPower&#039;&#039;&#039; und &#039;&#039;&#039;loadRelease&#039;&#039;&#039; ansehen.&lt;br /&gt;
&lt;br /&gt;
Zusammenfassend ist optPower vorwiegend für die Nutzergruppe geeignet, die eine tendenziell sparsamere Ladeleistung bevorzugen und dafür bereit sind eventuelle &amp;quot;Verluste&amp;quot; in Form von Einspeisung zu akzeptieren. &amp;lt;br&amp;gt;&lt;br /&gt;
Demgegenüber eignet sich das aggressivere smartPower für Anwender, die bei niedrigen PV-Erträgen bewusst das Maximum an Batterieladung anstreben und dafür in Kauf nehmen, dass Ladeleistungen weniger knapp kalkuliert sind. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Unterstützung des Modus &amp;quot;Eigennutzung&amp;quot; bei Hybrid-Wechselrichtern =====&lt;br /&gt;
Viele Hybrid-Wechselrichter verteilen die zur Verfügung stehende PV-Leistung nach folgendem Prioritäten, wenn der (übliche) Modus &amp;quot;Eigennutzung&amp;quot; aktiviert ist:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Nutzung der Leistung zur Deckung des Hausverbrauchs,&lt;br /&gt;
# Nutzung der Leistung zur Ladung des bzw. der angeschlossenen Speicher.&lt;br /&gt;
# Einspeisung der Leistung in das öffentliche Netz.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Da in aller Regel die Leistung, mit der ein angeschlossener Speicher geladen wird, limitiert werden kann, lassen sich die o.g. Priorität bzgl. des Speichers zugunsten einer Überschusseinspeisung aufweichen. Ein entstehender &amp;quot;Überschuss&amp;quot; steht also ggf. nur deshalb zur Verfügung, weil die Ladeleistung des Speichers begrenzt wurde.&lt;br /&gt;
&lt;br /&gt;
Ab Version 1.58.6 bietet SolarForecat die Möglichkeit, prognostizierte Verbräuche nicht mehr komplett bei der Bestimmung der &#039;&#039;optimalen Ladeleistung&#039;&#039; zu berücksichtigen, sondern nur noch zu einem prozentualen Anteil von 0..100 %. Hierzu muss der Attribut-Schlüssel &#039;&#039;&#039;ctrlBatSocManagementXX-&amp;gt;weightOwnUse=&amp;lt;Percentage&amp;gt;&#039;&#039;&#039; entsprechend gesetzt werden. &lt;br /&gt;
&lt;br /&gt;
So führt beispielsweise weightOwnUse=100 dazu, dass bei der Berechnung der optimalen Ladeleistung prognostizierte Verbräuche nicht mehr berücksichtigt werden indem sie bei der Bestimmung des stündlichen PV-Überschusses unberücksichtigt bleiben. Eine derartige Einstellung kann z.B. sinnvoll sein, wenn alle ansonsten täglich laufende Verbraucher zugunsten einer Batterieladung ausgeschaltet werden können.&lt;br /&gt;
&lt;br /&gt;
Ein Wert von zum Beispiel weightOwnUse=30 lässt 30% der stündlichen Verbrauchslast unberücksichtigt, sodass sich der kalkulierte PV-Überschuß pro Stunde um 30% des prognostizierten Verbrauchs erhöht. Da die Berechnung der optimierten Ladeleistung mit dem zur Verfügung stehenden PV-Überschuß gewichtet erfolgt, würde sich die kalkulierte Ladeleistung in den meisten Fällen ebenfalls um einen gewissen Betrag erhöhen sofern andere Faktoren dies nicht verhindern. Das kann beispielweise der Fall sein, wenn die kalkulierte Ladeleistung zu gering ist und automatisch aif mindestens &#039;&#039;&#039;setupBatteryDevXX-&amp;gt;pinreduced&#039;&#039;&#039; angehoben wurde.&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Welche Ladestrategie soll ich wählen? - eine Möglichkeit zur Best-Practice Findung mit Codebeispiel ====&lt;br /&gt;
&lt;br /&gt;
In den vorangegangenen Abschnitten wurden die verschiedenen Möglichkeiten zur Steuerung der Batterieladung und dem SoC vorgestellt. Diese Steuerungsvarianten optimieren die Arbeitweise der Batterie, haben aber jeweils einen eigenen Fokus auch wenn es gewisse Überschneidungen gibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Steuerungsvarianten lassen sich folgendermaßen klassifizieren:&lt;br /&gt;
&lt;br /&gt;
# Steuerung der Batterieladung über eine Ladefreigabe, die durch bestimmte Indikatoren festgelegt wird. Diese Variante ist in [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#PV-Prognose_und_Verbrauch_optimierte_Beladungssteuerung_unter_Berücksichtigung_einer_Wirkleistungsbegrenzung|diesem]] Abschnitt beschrieben.&lt;br /&gt;
# Steuerung der Batterieladung durch eine optimierte maximale Ladeleistung. Diese Variante ist in [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#leistungsoptimierte_Beladungssteuerung_mit_dem_Fokus_geringe_Verlustleistung_und_Verschleiß|diesem]] Abschnitt dargelegt. Zu dieser Variante gehören die Strategien &#039;&#039;optPower&#039;&#039; sowie &#039;&#039;smartPower&#039;&#039;. Die Unterschiede beider Strategien sind ebenfalls in dem verlinkten Abschnitt beschrieben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;&#039;Variante 1.)&#039;&#039;&#039; gibt die Ladung der Batterie frei wenn der (verbleibende) PV-Überschuß des Tages kleiner oder gleich dem Ladungsbedarf der Batterie ist um einen SoC von 100% bzw. den maximal möglichen SoC am Ende des Tages zu erreichen. Dadurch wird die in der Batterie vorhandene freie Kapazität so lange wie möglich der Einhaltung von besonderen Grenzwerten, z.B. des Einspeiselimits (plantControl-&amp;gt;feedinPowerLimit), vorbehalten. Nebeneffekt ist, dass plötzlich und unerwartet auftretende hohe Erzeugungsleistungen in die Batterie geladen werden können und nicht unerwünscht in das öffentliche Netz eingespeist werden. &lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;&#039;Variante 2.)&#039;&#039;&#039; lässt die Batterie kontinuierlich laden, wobei die Ladeleistung auf ein optimiertes Minimum reduziert wird ohne das Ziel, einen maximalen SoC am Tagesende zu erreichen, zu ignorieren. Dadurch wird die Batterie schonend, mit möglichst wenig Verlustleistung und verschleißarm geladen. Die Vorhaltung der freien Kapaziäten der Batterie sind in dieser Variante nicht die Prämisse. Die Einhaltung des gesetzten Enispeiselimits wird auch in dieser Variante beachtet sofern es der Ladezustand der Batterie zulässt. Technisch bedingt kann diese Variante nur ungenügend auf unerwartete PV-Überschüsse reagieren, was zu einer Einspeisung in das öffentliche Netz oder im ungünstigsten Fall zur Abregelung der Anlage führen kann. Mit dem Attribut &#039;&#039;&#039;ctrlBatSocManagementXX-&amp;gt;safetyMargin&#039;&#039;&#039; kann man diesem negativen Aspekt in gewissem Maße entgegenwirken.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ausgehend von diesen unterschiedlichen Optimierungszielen bietet sich die Variante 1.) vorwiegend in den Übergangs- und Wintermonaten an. Durch die beschriebenen Eigenschaften dieser Variante ist bei tendeziell weniger PV-Überschuß über den Tag die Ladung der Batterie komplett freigegeben, wodurch bei plötzlich auftretenden sonnige Abschnitten und Aufklarungen die Batterie sofort mit dem verfügbaren PV-Überschuß geladen wird. Auch eine Einspeisung über das Einspeiselimit hinaus kann verhindert werden. In der übrigen Zeit wird die Ladeleistung durch den verfügbaren PV-Überschuß begrenzt. &lt;br /&gt;
Weiterhin soll der SoC nicht dauerhaft tief absinken und ebenfalls nicht auf einem zu hohen Level verharren was auch einer maximal möglichen Energiespeicherung an sonnigen Tagen entgegenwirken würde.&lt;br /&gt;
In dieser Zeit ist die Nutzung der Kombination von [[SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Nutzung_des_Batterie_SOC-Management|SoC-Management]] und Variante 1.) wohl am Besten geeignet um die Ziele zu verwirklichen sowie Notreserven in den Batterien vorzuhalten. &lt;br /&gt;
&lt;br /&gt;
In den Sommermonaten hingegen ist üblicherweise sehr viel PV-Energie und Überschuß vorhanden. In dieser Periode würden die Batterien mit sehr hoher Leistung sehr zeitig am Tag vollgeladen. Die Variante 1.) ist im Prinzip ebenfalls gut geeignet den Zeitpunkt der Vollladung hinauszuzögern, jedoch erscheint die Varinte 2.) in dieser Zeit besser geeignet mit einer über den gesamten Tag verteilten moderaten Ladeleistung den Ziel-SoC zu erreichen. Auch diese Variante versucht eine Überschreitung des Einspeiselimits zu verhindern sofern der Ladezustand der Batterie dies ermöglicht.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Codebeispiel zur Steuerung eines in ein Victron System eingebundenen Pylontech Batteriestack via Cerbo GX =====&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;nachfolgende Codebeispiel&#039;&#039;&#039; bietet die Möglichkeit über ein Attribut die Ladevariante auszuwählen, über ein weiteres Attribut die SoC-Steuerung zu aktivieren/deaktivieren, integriert die Ladesteuerung für eine Batterie-Anforderungsladung bei Unterschreitung von ctrlBatSocManagementXX-&amp;gt;lowSoc, und ergänzt eine zellspannungsbasierte Ladestrom-Drosselung (&#039;&#039;&#039;TermVoltageTaper&#039;&#039;&#039;) zum Schutz der Einzelzellen nahe Vollladung.&lt;br /&gt;
&lt;br /&gt;
Die verwendeten Devices werden über eine MQTT Verbindung CerboGX -&amp;gt; FHEM erzeugt und aktualisiert. Der Code wurde mit Venus OS Version v3.72 auf Cerbo GX getestet bzw. mit dieser Version produktiv eingesetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesteuerte Batterieanlage besteht aus:&lt;br /&gt;
* 3 x Victron MultiPlusII 3000/48&lt;br /&gt;
* Steuergerät CerboGX (in FHEM über MQTT eingebunden)&lt;br /&gt;
* einem Batteriestack bestehend aus mehreren Pylontech US3000C (wird durch CerboGX gesteuert und über die separate MQTT-Verbindung als Batteriestack-Device eingebunden)&lt;br /&gt;
* zusätzlich, für TermVoltageTaper: das FHEM-Modul &#039;&#039;&#039;PylonLowVoltage&#039;&#039;&#039;, welches je US3000C-Pack über RS485 die 15 Einzelzellspannungen ausliest (Readings &#039;&#039;cellVoltage_01&#039;&#039; … &#039;&#039;cellVoltage_15&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zur Umschaltung bzw. Auswahl der Ladestrategie und des SoC-Managements werden zwei User-Attribute im SolarForecast Device angelegt.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr ... userattr userFn_BatterySoCManagement:Ein,Aus userFn_BatteryLoadManagement:Aus,loadRelease,optPower,smartPower&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Code werden diese Attribute ausgewertet. Das nachfolgende Script vereint folgende Funktionalitäten:&lt;br /&gt;
* die Aktivierung/Deaktivierung des SoC-Managements via Attribut userFn_BatterySoCManagement&lt;br /&gt;
* die Auswahl der Ladestrategie oder Deaktivierung der Ladesteuerung via Attribut userFn_BatteryLoadManagement&lt;br /&gt;
* Integration einer Anforderungsladung bei Signalisierung durch Reading Battery_ChargeRequest_XX&lt;br /&gt;
* eine zellspannungsbasierte Sicherheitsdrosselung des Ladestroms nahe Vollladung (&#039;&#039;&#039;TermVoltageTaper&#039;&#039;&#039;, siehe unten)&lt;br /&gt;
* Generierung von Readings userFn_Victron_GridSetpoint_set und userFn_MPII_MaxChargeCurrent_set zur Dokumentation der eingestellten Soll-Werte, sowie userFn_LoadController_* zur Dokumentation des TermVoltageTaper-Verhaltens&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bei der Nachnutzung des Scripts sind zunächst die &#039;&#039;&#039;Konstanten&#039;&#039;&#039; und die verwendeten Devices (z.B. MQTT2_cerboGX_c0619ab34e08_settings) sowie deren Readings im Block &#039;&#039;&#039;aktuelle Indikatoren&#039;&#039;&#039; anzupassen. Für TermVoltageTaper sind zusätzlich die drei Zellspannungs-Parameter (siehe unten) an die eigene Zellchemie und die eigenen Messwerte anzupassen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Script wird in die Datei &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039; eingetragen und im SolarForecast Attribut &#039;&#039;&#039;ctrlUserExitFn&#039;&#039;&#039; hinterlegt:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr ... ctrlUserExitFn {&lt;br /&gt;
                          ::batLoadMgmnt ($name, &#039;01&#039;);&lt;br /&gt;
                          # ::batLoadMgmnt ($name, &#039;02&#039;);   # optional für eine weitere Batterie &#039;02&#039;&lt;br /&gt;
                          # ::batLoadMgmnt ($name, &#039;0X&#039;);   # optional für weitere Batterien&lt;br /&gt;
                        }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit diesem Script ist der Nutzer in der Lage, das Batterie Lademanagement entsprechend seiner Motivation und gegebenenfalls abhängig von der Jahreszeit umzustellen und das Ergebnis bzw. die Zielerreichung zu testen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Attribut &#039;&#039;&#039;userFn_BatteryLoadManagement&#039;&#039;&#039; selektiert die gewünschte Ladestrategie:&lt;br /&gt;
;Aus: das Lademanagement ist ausgeschaltet&lt;br /&gt;
&lt;br /&gt;
;loadRelease: das Lademanagement Variante 1.) Ladestrategie Ladefreigabe ist aktiviert&lt;br /&gt;
&lt;br /&gt;
;optPower: das Lademanagement Variante 2.) Ladestrategie optimierte Ladeleistung ist aktiviert&lt;br /&gt;
&lt;br /&gt;
;smartPower: das Lademanagement Variante 2.) Ladestrategie zieloptimierte Ladeleistung ist aktiviert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die in SolarForecast eingestellte Ladestrategie (Attributschlüssel &#039;&#039;&#039;ctrlBatSocManagement01-&amp;gt;loadStrategy&#039;&#039;&#039;) wird in dem Steuerungscode in jedem Zyklus aktuell ausgelesen und berücksichtigt.&lt;br /&gt;
&lt;br /&gt;
Hat man die individuell passende Management-Strategie gefunden, bietet sich auch eine automatische (zum Beispiel durch einen Kalender oder Sonnenstand (Elevation) zur Mittagszeit) Umschaltung der Ladestrategie an. Die Unterschreitung der Elevation unter einen bestimmten Wert würde den Beginn des Winterhalbjahres und reverse Überschreitung den Beginn des Sommerhalbjahres kennzeichnen. Entsprechend würde dann die gewünschte Ladestrategie selektiert. Alternativ könnte auch die PV-Überschußprognose für den aktuellen Tag über das Reading &#039;&#039;Today_PVforecast&#039;&#039; für eine Entscheidung bzgl. der Ladestrategie herangezogen werden.&lt;br /&gt;
&lt;br /&gt;
Das SoC-Management kann über das gesamte Jahr aktiviert bleiben, hat jedoch nach bisherigen Erfahrungen nur im Winterhalbjahr eine starke Relevanz.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TermVoltageTaper - Zellschutz nahe Vollladung&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Motivation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ein hoher SoC-Stand allein ist bei LiFePO4-Zellen unkritisch. Problematisch sind vielmehr die bei ungünstigem Ladeverlauf auftretenden hohen &#039;&#039;&#039;Einzelzellspannungen&#039;&#039;&#039; nahe Vollladung – ein globales, SoC-basiertes Lademanagement (wie es SolarForecast über &#039;&#039;Battery_ChargeOptTargetPower_XX&#039;&#039; liefert) kennt die Streuung der Einzelzellen innerhalb eines Batteriestacks nicht und kann daher eine ausbrechende Einzelzelle nicht erkennen. TermVoltageTaper schließt diese Lücke, indem es den von SolarForecast vorgegebenen Ladestrom in der kritischen Endphase anhand der &#039;&#039;&#039;höchsten gemessenen Einzelzellspannung im gesamten Stack&#039;&#039;&#039; begrenzt. Die Lösung basiert auf dem Konzept des Forenusers &#039;&#039;&#039;Parallix&#039;&#039;&#039; (siehe [https://forum.fhem.de/index.php?msg=1359855 #5467] und [https://forum.fhem.de/index.php?msg=1358509 #5199]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Physikalischer Hintergrund: OCV-Kurve und Kniezone&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;&#039;OCV-Kurve&#039;&#039;&#039; (Open Circuit Voltage) beschreibt die Ruhespannung einer Zelle in Abhängigkeit vom SoC – also die Spannung ohne fließenden Strom, nach ausreichender Relaxationszeit. Bei LiFePO4-Zellen verläuft diese Kurve zwischen ca. 20 % und 90 % SoC sehr &#039;&#039;&#039;flach&#039;&#039;&#039;: Die Spannung ändert sich über einen weiten SoC-Bereich kaum, weshalb eine SoC-Schätzung über die Spannung in diesem Bereich unzuverlässig ist (die BMS-SoC-Schätzung basiert daher primär auf Coulomb-Zählung).&lt;br /&gt;
&lt;br /&gt;
Erst kurz vor Vollladung – der &#039;&#039;&#039;Kniezone&#039;&#039;&#039; – steigt die Spannung deutlich steiler an. Genau das macht die Zellspannung in diesem Bereich zu einem empfindlichen, geeigneten Steuersignal: Sie reagiert dort auf SoC- bzw. Ladezustandsänderungen viel stärker als im Flachbereich, und sie macht – anders als der globale Pack-SoC – auch &#039;&#039;&#039;Streuungen zwischen Einzelzellen&#039;&#039;&#039; sichtbar, da jede Zelle einzeln gemessen wird.&lt;br /&gt;
&lt;br /&gt;
[[File:OCV_Kniezone_TermVoltageTaper.png|thumb|420px|OCV-Kurve (grün) und Ladespannung inkl. IR-Drop (orange, gestrichelt) einer LiFePO4-Zelle über dem SoC. Ab ca. 90 % SoC beginnt die Kniezone mit deutlich steilerem Spannungsanstieg. lowerTermVoltage und upperTermVoltage begrenzen den TermVoltageTaper-Regelbereich.]]&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zur reinen Ruhespannung (OCV) liegt bei fließendem Ladestrom noch der &#039;&#039;&#039;IR-Drop&#039;&#039;&#039; (Spannungsabfall am Zell-Innenwiderstand, U_IR = I × R_innen) auf der gemessenen Klemmspannung – daher liegt die tatsächlich gemessene Ladespannung stets etwas über der reinen OCV-Kurve (siehe orangene, gestrichelte Kurve in der Grafik).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Regelparameter&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
TermVoltageTaper arbeitet mit drei zentralen Spannungsparametern (aktuell als lokale Variablen in der Sub definiert, nicht als Attribut):&lt;br /&gt;
&lt;br /&gt;
;LOWER_TERMVOLTAGE (aktuell 3.420 V): Zellspannung, ab der die Drosselung des Ladestroms einsetzt. Der Wert sollte deutlich unterhalb der bei ca. 99 % SoC beobachteten Zellspannung liegen (bei den hier verwendeten US3000C-Packs ca. 3.480 V) und idealerweise empirisch aus den eigenen Log-Daten (Zellspannung über Zeit/SoC während eines vollständigen Ladevorgangs) ermittelt werden.&lt;br /&gt;
&lt;br /&gt;
;UPPER_TERMVOLTAGE (aktuell 3.490 V): Höchste zulässige Zellspannung. Wird sie überschritten, wird der Ladestrom hart auf 0 gesetzt. Der Wert muss mit klarem Sicherheitsabstand unterhalb der BMS-eigenen Überspannungsschutzschwelle liegen (bei US3000C ca. 3.600 V je Zelle).&lt;br /&gt;
&lt;br /&gt;
;VOLTAGE_OFFSET (aktuell 0): IR-Drop-Kompensation für den linearen SoC-Bereich. Bei den in der Praxis auftretenden geringen Lade-C-Raten ist der IR-Drop meist im Bereich der Messauflösung und kann vernachlässigt werden; bei höheren Ladeströmen sollte dieser Wert ggf. SoC-abhängig ergänzt werden.&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 2026-08-09 153126.png|thumb|420px|Arbeitsbereich des TermVoltageTaper (orange eingekreist). Deutlich erkennbar ist die Abregelung von OTP auf &#039;OTP capped&#039; bei Überschreitung der VOLTAGE_OFFSET Rampe. Durch Einsatz der Hysterese UPPER_TERMVOLTAGE_HYST wird ein gleichmäßiger Regelverlauf realisiert.]]&lt;br /&gt;
&lt;br /&gt;
;UPPER_TERMVOLTAGE_HYST (aktuell 0.030 V): Hysterese-Band unterhalb von UPPER_TERMVOLTAGE zur Vermeidung von Oszillationen des Ladestroms. Ohne Hysterese würde eine Proportionalregelung an dieser harten oberen Schwelle zu einem Grenzzyklus neigen: Nach dem Cutoff (current = 0) relaxiert die Zellspannung durch den Wegfall des IR-Drops, unterschreitet dadurch kurzzeitig UPPER_TERMVOLTAGE, der Regler gibt sofort wieder vollen Strom frei, wodurch die Spannung erneut über die Schwelle steigt – der Zyklus beginnt von vorn, oft im Sekundentakt. Mit der Hysterese bleibt ein einmal ausgelöster Cutoff so lange aktiv (Schmitt-Trigger-Verhalten), bis maxCellVolt die niedrigere Freigabeschwelle (UPPER_TERMVOLTAGE − UPPER_TERMVOLTAGE_HYST) tatsächlich unterschreitet. Der aktuelle Zustand (aktiv/inaktiv) wird im Reading &#039;&#039;userFn_LoadController_cutoffActive&#039;&#039; dokumentiert. Der Wert ist ein empirisch ermittelter Startwert; ist die Oszillation trotzdem noch spürbar, kann UPPER_TERMVOLTAGE_HYST schrittweise erhöht werden, auf Kosten einer etwas trägeren Wiederfreigabe nach einem Cutoff. &lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 2026-08-09 184604.png|thumb|420px|Cutoff löst sich im Bereich der Volladung nur selten (OTP Capped steigt bis ca. 2786 W), bis bei übersteigen UPPER_TERMVOLTAGE erneut gecuttet wird. Jedes Mal, wenn sich der Cutoff löst, ist max. Zellenspannung spürbar unter die eingestellte Release-Schwelle (3.460 V) gefallen. Das ist erwünschtes, kontrolliertes Verhalten – kein Bug.]]&lt;br /&gt;
&lt;br /&gt;
Der Taper wirkt als lineare Rampe zwischen &#039;&#039;lowerTermVoltage&#039;&#039; und &#039;&#039;upperTermVoltage&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
current *= 1.0 - (maxCellVolt - lowerTermVoltage) / (upperTermVoltage - lowerTermVoltage);&lt;br /&gt;
current  = 0.0 if maxCellVolt &amp;gt; upperTermVoltage;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ermittlung der maximalen Zellspannung&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
TermVoltageTaper ermittelt &#039;&#039;maxCellVolt&#039;&#039; als Maximum über &#039;&#039;&#039;alle&#039;&#039;&#039; Zellen &#039;&#039;&#039;aller&#039;&#039;&#039; im System vorhandenen &#039;&#039;PylonLowVoltage&#039;&#039;-Devices (bei Parallelschaltung mehrerer US3000C-Packs am gemeinsamen DC-Bus muss die kritischste Einzelzelle über den gesamten Stack hinweg erkannt werden, nicht nur pro Pack). Dabei wird zusätzlich das Alter jedes einzelnen &#039;&#039;cellVoltage_XX&#039;&#039;-Readings geprüft (Parameter &#039;&#039;PYLON_MAXAGE&#039;&#039;, aktuell 300 Sekunden): Ist ein Reading älter, wird sein Wert ignoriert und protokolliert. Werden veraltete Werte gefunden, wird der Ladestrom sicherheitshalber unabhängig vom berechneten &#039;&#039;maxCellVolt&#039;&#039; auf &#039;&#039;batMinChgCurrent&#039;&#039; (aktuell 0) gesetzt – ein Fail-Safe-Verhalten, das eine durch Buskommunikationsprobleme (z. B. RS485-Kollisionen bei mehreren gleichzeitig pollenden Pack-Devices) bedingte Fehlmessung nie unbemerkt in einen zu hohen Ladestrom münden lässt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Einbindung in batLoadMgmnt&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
TermVoltageTaper wird als eigenständige Sub aufgerufen und liefert die um den Zellspannungs-Taper gedeckelte Ladeleistung (&#039;&#039;otpCapped&#039;&#039;) zurück:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
my $otpCapped = TermVoltageTaper ($name, $otp, $voltage);&lt;br /&gt;
$otpCapped    = List::Util::min ($otp, $otpCapped);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;otpCapped&#039;&#039; wird anstelle von &#039;&#039;otp&#039;&#039; in die anschließende GridSetpoint-Berechnung übernommen. Damit wirkt der Zellschutz &#039;&#039;&#039;innerhalb desselben Regelpfads&#039;&#039;&#039;, den SolarForecast ohnehin für die PV-Überschuss-basierte Ladesteuerung nutzt: Erreicht &#039;&#039;maxCellVolt&#039;&#039; die Kniezone, sinkt &#039;&#039;otpCapped&#039;&#039;, wodurch automatisch mehr PV-Leistung über den GridSetpoint Richtung Netz/Hausverbrauch statt in die Batterie geleitet wird – ohne zusätzlichen, parallelen Regelkreis.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtiger Hinweis bei DC-gekoppelten Anlagen mit separatem MPPT&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die GridSetpoint-basierte Drosselung wirkt auch dann korrekt, wenn zusätzlich zu den MultiPlusII-Geräten ein direkt am Batterie-DC-Bus hängender MPPT-Solarladeregler im System vorhanden ist. Da MPPT, Batterie und MultiPlusII am selben Gleichstrombus hängen, gilt näherungsweise:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Ladeleistung_Batterie ≈ Leistung_MPPT - Leistung_MultiPlusII&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Erhöht man über den GridSetpoint die vom MultiPlusII Richtung Netz/Hausverbrauch gewandelte Leistung, sinkt automatisch der für die Batterie verbleibende Rest – auch der vom MPPT erzeugte Anteil wird dabei über den MultiPlusII abgeführt und steht folglich nicht mehr für die Batterieladung zur Verfügung. Ein separater Eingriff am MPPT selbst ist für den regulären Taper-Betrieb also nicht erforderlich.&lt;br /&gt;
&lt;br /&gt;
Diese indirekte Drosselung ist zudem verlustfrei: Die abgeregelte Leistung wird nicht am MPPT verworfen (kein Curtailment), sondern produktiv ins Netz oder den Haushalt geleitet.&lt;br /&gt;
&lt;br /&gt;
Die Methode stößt jedoch an eine Grenze, sobald die &#039;&#039;&#039;maximale Einspeiseleistung&#039;&#039;&#039; (Attribut/Reading &#039;&#039;feedinPowerLimit&#039;&#039; bzw. bei Zero-Feed-in-Konfigurationen der Wert 0) bereits ausgeschöpft ist bzw. der GridSetpoint seinen zulässigen negativen Grenzwert (&#039;&#039;neggspmax&#039;&#039;) erreicht hat: In diesem Fall kann die vom MPPT erzeugte Leistung nicht mehr vollständig abgeführt werden, und ein Rest-Ladestrom bleibt trotz &#039;&#039;current = 0&#039;&#039; bestehen. Für den harten Cutoff-Fall (&#039;&#039;maxCellVolt &amp;gt; upperTermVoltage&#039;&#039;) ist dieser Grenzfall relevant und sollte bedacht werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Auswertung / Monitoring&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Für die Beobachtung des Regelverhaltens legt TermVoltageTaper folgende Readings an (mit Event-Erzeugung, &#039;&#039;readingsEndUpdate ($hash, 1)&#039;&#039;, damit FileLog/DbLog diese erfassen können):&lt;br /&gt;
&lt;br /&gt;
;userFn_LoadController_maxCellVolt: aktuell ermittelte maximale Zellspannung im Stack (V)&lt;br /&gt;
&lt;br /&gt;
;userFn_LoadController_maxCellSrc: Pack/Zelle, aus der die maximale Zellspannung stammt (z. B. &#039;&#039;Pylon3:cellVoltage_06&#039;&#039;), hilfreich zur Diagnose bei auffälligem Verhalten einzelner Packs&lt;br /&gt;
&lt;br /&gt;
;userFn_LoadController_otp: vom Modul errechnete optimale Ladeleistung (W) zur Erreichung des Ladeziels ohne Kenntnis der Zellspannungen&lt;br /&gt;
&lt;br /&gt;
;userFn_LoadController_otpCapped: daraus resultierende gedeckelte Ladeleistung (W), die in die weitere GridSetpoint-Berechnung einfließt&lt;br /&gt;
&lt;br /&gt;
;userFn_LoadController_cutoffActive: dokumentiert den Hysterese-Zustand des harten Spannungs-Cutoffs (1 = ausgelöst, Ladeleistung auf 0 W reduziert; 0 = nicht aktiv). &#039;&#039;&#039;Zu beachten:&#039;&#039;&#039; otpCapped kann auch bei cutoffActive=0 den Wert 0 annehmen, nämlich wenn der Stale-Data-Fail-Safe greift (veraltete Zellspannungsdaten) oder wenn die Taper-Rampe rechnerisch auf 0 rundet, ohne dass UPPER_TERMVOLTAGE überschritten wurde. cutoffActive zeigt also ausschließlich, ob speziell der Hysterese-Mechanismus gerade aktiv ist – nicht jede Ursache für otpCapped=0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ein gemeinsamer Plot aus &#039;&#039;userFn_LoadController_maxCellVolt&#039;&#039;, &#039;&#039;userFn_LoadController_current&#039;&#039; bzw. &#039;&#039;userFn_LoadController_otpCapped&#039;&#039; sowie &#039;&#039;Battery_ChargeOptTargetPower_XX&#039;&#039; (als ungedrosselter Referenzwert) zeigt den Taper-Effekt sehr anschaulich: Bis zum Erreichen von &#039;&#039;lowerTermVoltage&#039;&#039; laufen beide Kurven deckungsgleich, danach knickt &#039;&#039;otpCapped&#039;&#039; zunehmend unter den ungedrosselten Zielwert ab, bis bei Erreichen von &#039;&#039;upperTermVoltage&#039;&#039; der harte Cutoff auf 0 greift.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible mw-collapsed&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Code Lademanagement -&amp;gt;&#039;&#039;&#039; &amp;lt;div class=&amp;quot;mw-collapsible-content&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
###############################################################################&lt;br /&gt;
#&lt;br /&gt;
# Save this file as 99_mySolarForecastUtils.pm, and create your own functions&lt;br /&gt;
# in the new file. They are then available in every Perl expression.&lt;br /&gt;
#&lt;br /&gt;
###############################################################################&lt;br /&gt;
 package main;&lt;br /&gt;
 use strict;&lt;br /&gt;
 use warnings;&lt;br /&gt;
 use feature &#039;state&#039;;&lt;br /&gt;
&lt;br /&gt;
 sub&lt;br /&gt;
 mySolarForecastUtils_Initialize($$)&lt;br /&gt;
 {&lt;br /&gt;
   my ($hash) = @_;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
# ab hier eigenen Code eintragen&lt;br /&gt;
&lt;br /&gt;
############################################################################&lt;br /&gt;
#      komplettes Batterie Lademanagement (SOC + Ladeleistung)&lt;br /&gt;
############################################################################&lt;br /&gt;
sub batLoadMgmnt {&lt;br /&gt;
  my $name = shift;&lt;br /&gt;
  my $bn   = shift // &#039;01&#039;;                                            # Batterienummer&lt;br /&gt;
  my $hash = $defs{$name};&lt;br /&gt;
  &lt;br /&gt;
  ## Konstanten&lt;br /&gt;
  ###############  &lt;br /&gt;
  use constant {&lt;br /&gt;
    GSPDEF                 =&amp;gt; 20,                       # Default Einstellung des Grid Setpoint&lt;br /&gt;
    FINDEF                 =&amp;gt; 5000,                     # Default Einspeiselimit&lt;br /&gt;
    MINSOCDEF              =&amp;gt; 10,                       # Default Minimum SoC&lt;br /&gt;
    MAXPLDEF               =&amp;gt; 105,                      # max. Ladestrom (A) für Victron MPII Verbund&lt;br /&gt;
    SYS_VOLTAGE            =&amp;gt; 48,                       # Batterie Systemspannung&lt;br /&gt;
    PYLON_MAXAGE           =&amp;gt; 300,                      # max. erlaubtes Alter (s) eines cellVoltage-Readings&lt;br /&gt;
    LOWER_TERMVOLTAGE      =&amp;gt; 3.420,                    # Zellspannung -&amp;gt; Start Drosselung, deutlich vor 3480 mV bei 99 %&lt;br /&gt;
    UPPER_TERMVOLTAGE      =&amp;gt; 3.490,                    # höchste Zellspannung (oberhalb keine weitere Ladung)&lt;br /&gt;
                                                        # ... (nahe dem vom Hersteller intendierten &amp;quot;voll&amp;quot;-Punkt, mit klarem &lt;br /&gt;
                                                        # ... Sicherheitsabstand zur 3600 mV Schutzschwelle)&lt;br /&gt;
    VOLTAGE_OFFSET         =&amp;gt; 0,                        # Spannungsabfall am Innenwiderstand der Zelle für ein SOC in [20,90] &lt;br /&gt;
                                                        # ... andernfalls VOLTAGE_OFFSET=0&lt;br /&gt;
	UPPER_TERMVOLTAGE_HYST =&amp;gt; 0.030,                    # Hysterese-Band um UPPER_TERMVOLTAGE (V)&lt;br /&gt;
  };&lt;br /&gt;
  &lt;br /&gt;
  my $batsocmgmt  = AttrVal ($name, &#039;userFn_BatterySoCManagement&#039;,  &#039;Aus&#039;);             # Aus / Ein&lt;br /&gt;
  my $batloadmgmt = AttrVal ($name, &#039;userFn_BatteryLoadManagement&#039;, &#039;Aus&#039;);             # Soll: Aus|loadRelease|(opt|smart)Power&lt;br /&gt;
  my $vicsets     = &#039;MQTT2_cerboGX_c0619ab34e08_settings&#039;;                              # Device Victron CerboGX Einstellungen&lt;br /&gt;
  my $batterydev  = &#039;MQTT2_cerboGX_c0619ab34e08_battery&#039;;                               # Device für Pylontech BatteryStack&lt;br /&gt;
  my $ctype       = &#039;Aus&#039;;                                                              # Voreinstellung Steuerungstyp  &lt;br /&gt;
  my $voltage     = ReadingsNum ($batterydev, &#039;DC_Voltage_value&#039;, SYS_VOLTAGE);         # akt. Batteriespannung Bat-Paket (V) &lt;br /&gt;
&lt;br /&gt;
  ## Ladestrategie Ist-Einstellung und Soll-Abgleich&lt;br /&gt;
  ####################################################&lt;br /&gt;
  my $cgbt     = AttrVal ($name, &#039;ctrlBatSocManagement&#039;.$bn, undef);&lt;br /&gt;
  my $strategy = &#039;loadRelease&#039;; &lt;br /&gt;
&lt;br /&gt;
  if ($cgbt) {&lt;br /&gt;
    my $parsed = FHEM::SolarForecast::__parseAttrBatSoc ($name, $cgbt);                 # aktuell gesetzte Strategie ermitteln&lt;br /&gt;
    $strategy  = $parsed-&amp;gt;{loadStrategy} // $strategy;&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  if ($batloadmgmt ne &#039;Aus&#039;) {&lt;br /&gt;
    $ctype = $batloadmgmt;&lt;br /&gt;
	&lt;br /&gt;
    if ($strategy ne $batloadmgmt) {&lt;br /&gt;
      CommandSet (undef, &amp;quot;$name attrKeyVal ctrlBatSocManagement${bn} loadStrategy=$batloadmgmt&amp;quot;); &lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  ## aktuelle Indikatoren&lt;br /&gt;
  ##########################&lt;br /&gt;
  my $finplim = FHEM::SolarForecast::CurrentVal ($name, &#039;feedinPowerLimit&#039;,   FINDEF);  # Limit plantControl-&amp;gt;feedinPowerLimit (W)&lt;br /&gt;
  my $preduce = FHEM::SolarForecast::BatteryVal ($name, $bn, &#039;bpinreduced&#039;, MAXPLDEF);  # reduzierte Ladeleistung aus Bat-Konfig (W)&lt;br /&gt;
  &lt;br /&gt;
  my $surp       = ReadingsNum ($name, &#039;Current_Surplus&#039;,                 0);           # aktueller PV-Überschuß&lt;br /&gt;
  my $bcrq       = ReadingsNum ($name, &#039;Battery_ChargeRequest_&#039;.$bn,      0);           # Notfallladung&lt;br /&gt;
  my $unrestrict = ReadingsNum ($name, &#039;Battery_ChargeUnrestricted_&#039;.$bn, 0);           # Ladefreigabe (1 -&amp;gt; Bat Ladefreigabe)&lt;br /&gt;
  my $curgsp     = ReadingsNum ($vicsets, &#039;GridSetpoint&#039;, GSPDEF);                      # aktuelle Einstellung Grid Setpoint&lt;br /&gt;
  my $otp        = ReadingsNum ($name, &#039;Battery_ChargeOptTargetPower_&#039;.$bn, $preduce);  # optimale Ladeleistung (W)&lt;br /&gt;
  my $actmcc     = ReadingsNum ($vicsets, &#039;MaxChargeCurrent&#039;, 0);                       # akt. maximale Ladestromeinstellung&lt;br /&gt;
  my $load       = MAXPLDEF;                                                            # initialer Soll-Ladestrom MPII (A)&lt;br /&gt;
  my $neggspmax  = -1 * $finplim;&lt;br /&gt;
  &lt;br /&gt;
  my $gridsetpoint = GSPDEF;                                                            # Voreinstellung Grid Setpoint&lt;br /&gt;
  &lt;br /&gt;
  ####################################&lt;br /&gt;
  ##     Battery SoC Management&lt;br /&gt;
  #################################### &lt;br /&gt;
  if ($batsocmgmt eq &#039;Ein&#039;) { &lt;br /&gt;
    my $csoc = ReadingsNum ($vicsets, &#039;MinimumSocLimit&#039;,               MINSOCDEF);     # akt. SoC&lt;br /&gt;
    my $osoc = ReadingsNum ($name,    &#039;Battery_OptimumTargetSoC_&#039;.$bn, MINSOCDEF);     # optimierter Mindest-SoC&lt;br /&gt;
	&lt;br /&gt;
    if ($csoc != $osoc) {&lt;br /&gt;
      CommandSet (undef, &amp;quot;$vicsets MinimumSocLimit $osoc&amp;quot;);&lt;br /&gt;
      Log3 ($name, 3, qq{$name - userFn SoCMgmnt -&amp;gt; MinimumSocLimit in $vicsets set to $osoc %});&lt;br /&gt;
    }                                       &lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  ####################################&lt;br /&gt;
  ##     Battery Lade-Management&lt;br /&gt;
  #################################### &lt;br /&gt;
  &lt;br /&gt;
  #  TermVoltageTaper - Ladestrom-Drosselung anhand Zellspannung (Kniezone)&lt;br /&gt;
  #  Konzept nach Forenuser &#039;Parallix&#039;&lt;br /&gt;
  ############################################################################&lt;br /&gt;
  my $otpCapped = TermVoltageTaper ($name, $otp, $voltage, $bn);                       # OTP eventuell drosseln	&lt;br /&gt;
  $otpCapped    = List::Util::min  ($otp, $otpCapped);                                 # $otp mit der Taper-Grenze deckeln, &lt;br /&gt;
                                                                                       # BEVOR GridSetpoint/Load daraus berechnet werden&lt;br /&gt;
  &lt;br /&gt;
  ## Steuerung nach Ladungsfreigabe&lt;br /&gt;
  ###################################    &lt;br /&gt;
  if ($batloadmgmt eq &#039;loadRelease&#039;) {&lt;br /&gt;
    if (!$unrestrict) {                                                                 # Grid Setpoint absenken bis&lt;br /&gt;
                                                                                        # ... Ladeleistung = 0  &lt;br /&gt;
		$gridsetpoint = GSPDEF - $surp;                                                &lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  ## Steuerung nach optimaler Ladeleistung&lt;br /&gt;
  ##########################################&lt;br /&gt;
  if ($batloadmgmt =~ /(?:opt|smart)Power/xs) {&lt;br /&gt;
    if (!$unrestrict) {                                                                 # Grid Setpoint absenken bis&lt;br /&gt;
        my $gridin = $surp - $otpCapped;                                                # ... Ladeleistung = otpCapped                                               &lt;br /&gt;
		$gridsetpoint = GSPDEF - $gridin;                                               &lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  ## max. Ladestrom der MultiPlusII rechnen&lt;br /&gt;
  ###########################################&lt;br /&gt;
  if ($batloadmgmt ne &#039;Aus&#039;) {&lt;br /&gt;
    $load = $otpCapped / $voltage;                                                      # Ladestrombegrenzung MPII&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  ## Anforderungsladung (überschreibt max. Ladestrom)&lt;br /&gt;
  #####################################################&lt;br /&gt;
  if ($bcrq) {                                                                          # max. Ladeleistung b. Battery_ChargeRequest&lt;br /&gt;
    $ctype = &#039;requestCharging&#039;; &lt;br /&gt;
    &lt;br /&gt;
	if ($surp &amp;lt; $preduce) {&lt;br /&gt;
	  my $p = $preduce;&lt;br /&gt;
	  $load = $p / $voltage;														    # Soll-Ladestrom (A)&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  ## GridSetpoint und max. Ladestrom der MultiPlusII umsetzen&lt;br /&gt;
  #############################################################&lt;br /&gt;
  $gridsetpoint = List::Util::min (GSPDEF, $gridsetpoint);                              # GridSetpoint darf nicht &amp;gt; GSPDEF sein &lt;br /&gt;
  $gridsetpoint = List::Util::max ($neggspmax, $gridsetpoint);                          # GridSetpoint darf nicht &amp;lt; max. Einspeiseleistung sein&lt;br /&gt;
  $gridsetpoint = sprintf &amp;quot;%.0f&amp;quot;, $gridsetpoint;&lt;br /&gt;
  &lt;br /&gt;
  $load      = List::Util::max (0, List::Util::min (MAXPLDEF, $load));                  # clampen&lt;br /&gt;
  $load      = sprintf &amp;quot;%.0f&amp;quot;, $load;&lt;br /&gt;
  &lt;br /&gt;
  if ($curgsp != $gridsetpoint) {                                                       # GridSetpoint setzen&lt;br /&gt;
	  fhem (&amp;quot;set $vicsets GridSetpoint $gridsetpoint&amp;quot;);&lt;br /&gt;
      Log3 ($name, 3, qq{$name - userFn ChargeMgmnt &#039;$ctype&#039; -&amp;gt; GridSetpoint in $vicsets set to $gridsetpoint});&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  if ($load != $actmcc) {&lt;br /&gt;
    CommandSet (undef, &amp;quot;$vicsets MaxChargeCurrent $load&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
    Log3 ($name, 3, qq{$name - userFn ChargeMgmnt &#039;$ctype&#039; -&amp;gt; MaxChargeCurrent MultiPlusII in $vicsets set }.&lt;br /&gt;
                    qq{from old $actmcc A to $load A});&lt;br /&gt;
  }	&lt;br /&gt;
  &lt;br /&gt;
  readingsBeginUpdate ($hash);&lt;br /&gt;
  readingsBulkUpdate  ($hash, &#039;userFn_Victron_GridSetpoint_set&#039;, $gridsetpoint);&lt;br /&gt;
  readingsBulkUpdate  ($hash, &#039;userFn_MPII_MaxChargeCurrent_set&#039;,        $load);&lt;br /&gt;
  readingsEndUpdate   ($hash, 0);&lt;br /&gt;
  &lt;br /&gt;
return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
############################################################################&lt;br /&gt;
#  TermVoltageTaper - Ladestrom-Drosselung anhand Zellspannung (Kniezone)&lt;br /&gt;
#  Idee/Konzept: https://forum.fhem.de/index.php?msg=1358509&lt;br /&gt;
#                https://forum.fhem.de/index.php?msg=1359855&lt;br /&gt;
#  Konzept nach Forenuser &#039;Parallix&#039;&lt;br /&gt;
#  Eingang: OTP, Bat-Spannung&lt;br /&gt;
#  return: gedrosselter OTP &lt;br /&gt;
############################################################################  &lt;br /&gt;
sub TermVoltageTaper {&lt;br /&gt;
  my ($name, $otp, $voltage, $bn) = @_;&lt;br /&gt;
  &lt;br /&gt;
  my $current = $otp / $voltage;&lt;br /&gt;
  my $hash    = $defs{$name};&lt;br /&gt;
  &lt;br /&gt;
  my $termVoltageRange = UPPER_TERMVOLTAGE - LOWER_TERMVOLTAGE;&lt;br /&gt;
  my $releaseVoltage   = UPPER_TERMVOLTAGE - UPPER_TERMVOLTAGE_HYST;&lt;br /&gt;
  my $batMinChgCurrent = 0;&lt;br /&gt;
  &lt;br /&gt;
  state @allPylonDevs;&lt;br /&gt;
  @allPylonDevs = devspec2array (&amp;quot;TYPE=PylonLowVoltage&amp;quot;) if !@allPylonDevs;&lt;br /&gt;
&lt;br /&gt;
  my $maxCellVolt = 0;&lt;br /&gt;
  my $maxCellSrc  = &#039;&#039;;&lt;br /&gt;
  my $staleFound  = 0;&lt;br /&gt;
&lt;br /&gt;
  for my $pd (@allPylonDevs) {&lt;br /&gt;
    for my $cells (1..15) {&lt;br /&gt;
      my $cell = sprintf &amp;quot;%02d&amp;quot;, $cells;&lt;br /&gt;
      my $rn   = &amp;quot;cellVoltage_$cell&amp;quot;;&lt;br /&gt;
      my $age  = ReadingsAge ($pd, $rn, PYLON_MAXAGE + 1);                               # Alter in Sekunden&lt;br /&gt;
      &lt;br /&gt;
	  if ($age &amp;gt; PYLON_MAXAGE) {&lt;br /&gt;
        $staleFound = 1;&lt;br /&gt;
        &lt;br /&gt;
        Log3 ($name, 2, &amp;quot;$name - batTaper[$bn]: $pd $rn is outdated (${age}s) - value will be ignored&amp;quot;)&lt;br /&gt;
             if(FHEM::SolarForecast::askLogtime ($name, &amp;quot;ageIutdated_$pd&amp;quot;, PYLON_MAXAGE - 10)); &lt;br /&gt;
        &lt;br /&gt;
        next;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      my $v = ReadingsNum ($pd, $rn, 0);&lt;br /&gt;
      &lt;br /&gt;
	  if ($v &amp;gt; $maxCellVolt) {&lt;br /&gt;
        $maxCellVolt = $v;&lt;br /&gt;
        $maxCellSrc  = &amp;quot;$pd:$rn&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  # Fail-safe: Wenn veraltete Daten gefunden wurden, sicherheitshalber Strom kappen,&lt;br /&gt;
  # unabhängig vom (evtl. unvollständig ermittelten) $maxCellVolt&lt;br /&gt;
  if ($staleFound) {&lt;br /&gt;
    $current = $batMinChgCurrent;&lt;br /&gt;
    Log3 ($name, 2, &amp;quot;$name - batTaper[$bn]: outdated cell voltage data - set charge current to minimum as a precaution&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  Log3 ($name, 4, &amp;quot;$name - batTaper[$bn]: maxCellVolt=$maxCellVolt V ($maxCellSrc)&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
  ## Taper-Rampe&lt;br /&gt;
  ################&lt;br /&gt;
  if ($maxCellVolt &amp;gt; LOWER_TERMVOLTAGE + VOLTAGE_OFFSET) {&lt;br /&gt;
    $current *= 1.0 - ($maxCellVolt - LOWER_TERMVOLTAGE) / $termVoltageRange;&lt;br /&gt;
    $current = $current &amp;lt; $batMinChgCurrent ? $batMinChgCurrent : $current;&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  ## Hysterese um UPPER_TERMVOLTAGE (Schmitt-Trigger)&lt;br /&gt;
  #######################################################&lt;br /&gt;
  my $cutoffActive = $hash-&amp;gt;{HELPER}{&#039;TVT_CUTOFF&#039;.$bn} // 0;&lt;br /&gt;
&lt;br /&gt;
  if ($cutoffActive) {&lt;br /&gt;
    if ($maxCellVolt &amp;lt;= $releaseVoltage) {&lt;br /&gt;
      $cutoffActive = 0;                                                              # Freigabe: unter Release-Schwelle gefallen&lt;br /&gt;
      Log3 ($name, 4, &amp;quot;$name - batTaper[$bn]: TermVoltageTaper cutoff released (maxCellVolt=$maxCellVolt &amp;lt;= $releaseVoltage)&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    else {&lt;br /&gt;
      $current = 0.0;                                                                 # weiterhin gesperrt, solange über Release-Schwelle&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  elsif ($maxCellVolt &amp;gt; UPPER_TERMVOLTAGE) {&lt;br /&gt;
    $cutoffActive = 1;&lt;br /&gt;
    $current      = 0.0;&lt;br /&gt;
    &lt;br /&gt;
	Log3 ($name, 3, &amp;quot;$name - batTaper[$bn]: TermVoltageTaper cutoff engaged (maxCellVolt=$maxCellVolt &amp;gt; &amp;quot;&lt;br /&gt;
	                .UPPER_TERMVOLTAGE.&amp;quot;)&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  $hash-&amp;gt;{HELPER}{&#039;TVT_CUTOFF&#039;.$bn} = $cutoffActive;&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  $current      = sprintf &amp;quot;%.0f&amp;quot;, $current;&lt;br /&gt;
  my $otpCapped = List::Util::min ($otp, $current * $voltage);&lt;br /&gt;
  &lt;br /&gt;
  readingsBeginUpdate ($hash);&lt;br /&gt;
  readingsBulkUpdate  ($hash, &#039;userFn_LoadController_maxCellVolt&#039;,   $maxCellVolt);&lt;br /&gt;
  readingsBulkUpdate  ($hash, &#039;userFn_LoadController_maxCellSrc&#039;,     $maxCellSrc);&lt;br /&gt;
  readingsBulkUpdate  ($hash, &#039;userFn_LoadController_otpCapped&#039;,       $otpCapped);&lt;br /&gt;
  readingsBulkUpdate  ($hash, &#039;userFn_LoadController_otp&#039;,                   $otp);&lt;br /&gt;
  readingsBulkUpdate  ($hash, &#039;userFn_LoadController_cutoffActive&#039;, $cutoffActive);&lt;br /&gt;
  readingsEndUpdate   ($hash, 0);&lt;br /&gt;
&lt;br /&gt;
return $otpCapped;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
###############################################################################&lt;br /&gt;
# Ende eigener Code&lt;br /&gt;
&lt;br /&gt;
1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== barrierSoC - der Parameter den nicht jeder braucht  ====&lt;br /&gt;
&lt;br /&gt;
Wie bereits hinlänglich beschrieben, aktiviert das Attribut &#039;&#039;&#039;ctrlBatSocManagementXX&#039;&#039;&#039; mit diversen Schlüsseln die Batterie SoC- und Ladesteuerung. Für die alltägliche Nutzung und um schnell sichtbare Ergebnisse zu erzielen, ist die die Verwendung der obligatorischen Schlüssel lowSoc, upSoC und vielleicht noch die Auswahl der gewünschten Ladestrategie zunächst völlig ausreichend. Das Modul stellt für die Batteriesteuerung aber noch einige weitere Schlüssel zu Verfügung, die besondere Anforderungen an die Batteriesteuerung unterstützen. Einer dieser Parameter ist der &#039;&#039;&#039;barrierSoC&#039;&#039;&#039; Schlüssel.&lt;br /&gt;
&lt;br /&gt;
Wird eine der beschriebenen Batterie Ladestrategien &#039;&#039;optPower&#039;&#039; oder &#039;&#039;smartPower&#039;&#039; eingesetzt, wird die Batterieladungsleistung vom aktuell vorhandenen SoC bis zum Ziel-SoC optmiert im Reading Battery_ChargeOptTargetPower_XX bereitgestellt. Dabei wird auch eine eventuell in &#039;&#039;ctrlBatSocManagementXX-&amp;gt;loadTarget&#039;&#039; eingestellte Zielzeit berücksichtigt. Möglicherweise besteht der Wunsch die Batterieladung bis zu einem bestimmten Mindest-SoC so schnell wie möglich aufzuladen um z.B. zügig eine Netzausfallreserve aufzubauen. &lt;br /&gt;
&lt;br /&gt;
Zu diesem Zweck kann der optionale Parameter &#039;&#039;ctrlBatSocManagementXX-&amp;gt;barrierSoC&#039;&#039; verwendet werden. In dem Ladebereich&lt;br /&gt;
&lt;br /&gt;
  lowSoC &amp;lt;= SoC &amp;lt; barrierSoC&lt;br /&gt;
&lt;br /&gt;
kann der User Einfluß auf die berechnete Ladeleistung nehmen und sie ggf. bis zur maximal möglichen Leistung abändern. Das bedeutet alle Manipulationen erfolgen ausschließlich diesem SoC-Bereich.&lt;br /&gt;
Dazu kann dem Parameter mit einer bestimmten Syntax das Änderungsverhalten vorgegeben werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
barrierSoC=XX:&amp;lt;Aktion&amp;gt;:&amp;lt;Wert&amp;gt; oder&lt;br /&gt;
barrierSoC=XX:&amp;lt;Aktion&amp;gt;:&amp;lt;Reading&amp;gt;:&amp;lt;default&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dabei bedeutet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
XX - der Wert von barrierSoC in %. Es gilt lowSoC &amp;lt; XX &amp;lt; maxSoC&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit der &#039;&#039;&#039;&amp;lt;Aktion&amp;gt;&#039;&#039;&#039; wird eine der möglichen Manipulations-Varianten festgelegt:&lt;br /&gt;
&lt;br /&gt;
;max: - das Ladeleistungslimit wird auf setupBatteryDevXX-&amp;gt;pinmax festgelegt&lt;br /&gt;
;set: - das Ladeleistungslimit wird auf einen festen Wert oder Readingswert gesetzt&lt;br /&gt;
;inc: - das Ladeleistungslimit wird um einen festen Wert oder Readingswert erhöht&lt;br /&gt;
;dec: - das Ladeleistungslimit wird um einen festen Wert oder Readingswert verringert&lt;br /&gt;
;prc: - das Ladeleistungslimit wird um einen prozentualen Wert / Readingswert geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Aktion (außer &#039;&#039;max&#039;&#039;) wird auf den angegeben Wert bzw. den Wert des angegebenen Readings angewendet. Das Reading muß im SolarForecast Device enthalten sein. Bei Verwendung eines Readings wird mit &#039;&#039;&amp;lt;default&amp;gt;&#039;&#039; der Standardrückgabewert festgelegt falls das Reading keinen Wert liefert oder nicht vorhanden ist.&lt;br /&gt;
&lt;br /&gt;
Hier sind einige Beispiele für einen barrierSoC. Zur Vereinfachung wird ein barrierSoC von 40 % verwendet und kann natürlich auf einen anderen passenden Wert abgeändert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	barrierSoC=40:max:-                      -&amp;gt; das Ladeleistungslimit wird auf setupBatteryDevXX-&amp;gt;pinmax gesetzt&lt;br /&gt;
	barrierSoC=40:set:&amp;lt;Reading&amp;gt;:&amp;lt;default&amp;gt;    -&amp;gt; das Ladeleistungslimit auf den Wert &amp;lt;Reading&amp;gt; setzen&lt;br /&gt;
	barrierSoC=40:set:1350                   -&amp;gt; das Ladeleistungslimit wird auf 1350 W gesetzt&lt;br /&gt;
	barrierSoC=40:inc:&amp;lt;Reading&amp;gt;:&amp;lt;default&amp;gt;    -&amp;gt; das Ladeleistungslimit um den Wert &amp;lt;Reading&amp;gt; erhöhen&lt;br /&gt;
	barrierSoC=40:inc:200                    -&amp;gt; das Ladeleistungslimit wird um 200 W erhöht&lt;br /&gt;
	barrierSoC=40:dec:&amp;lt;Reading&amp;gt;:&amp;lt;default&amp;gt;    -&amp;gt; das Ladeleistungslimit um den Wert &amp;lt;Reading&amp;gt; verringern&lt;br /&gt;
	barrierSoC=40:dec:100                    -&amp;gt; das Ladeleistungslimit wird um 100 W verringert&lt;br /&gt;
	barrierSoC=40:prc:&amp;lt;Reading&amp;gt;:&amp;lt;default&amp;gt;    -&amp;gt; das Ladeleistungslimit um &amp;lt;Reading&amp;gt; Prozent ändern (+ erhöhen, - verringern)&lt;br /&gt;
	barrierSoC=40:prc:50                     -&amp;gt; das Ladeleistungslimit um 50% ändern (+ erhöhen, - verringern) &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== sequentielle Batterie-Ladung mehrerer Batterien mit lcSlot ====&lt;br /&gt;
&lt;br /&gt;
Der Parameter &#039;&#039;&#039;ctrlBatSocManagementXX-&amp;gt;lcSlot&#039;&#039;&#039; (&amp;quot;load control Slot&amp;quot;) definiert eine Zeitperiode am aktuellen Tag in der die Steuerungslogik für die Batteriesteuerung aktiviert ist. Ist dieser Parameter nicht gesetzt, ist das eingestellte Lademanagement über den gesamten Tag aktiert und wäre identisch mit der Einstellung:&lt;br /&gt;
&lt;br /&gt;
 lcSlot=00:00-23:59&lt;br /&gt;
&lt;br /&gt;
Somit ist die Ladesteuerung per default über den gesamten Tag aktiv.&lt;br /&gt;
&lt;br /&gt;
Durch das Setzen von lcSlot auf einen täglichen Slot wird die Ladesteuerung auf diese Periode eingegrenzt. In der übrigen Zeit ist die Ladung der Batterie freigegeben (Reading Battery_ChargeUnrestricted_XX) bzw. auf die maximal konfigurierte Ladeleistung eingestellt (Reading Battery_ChargeOptTargetPower_XX). Diese Readings können je nach verwendeter Ladestrategie ausgewertet und zur Steuerung der Batterie(n) verwendet werden.  &lt;br /&gt;
Die SoC-Steuerung wird durch die lcSlot-Angabe nicht beeinflusst.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit lcSlot kann zum Beispiel ein sequentielles Laden von mehreren Batterien umgesetzt werden. Nachfolgend wird ein solches Szenario mit drei Batterien  skizziert:&lt;br /&gt;
&lt;br /&gt;
1. die Batterie 1 soll mit voller Leistung geladen werden, die anderen Batterien nur bei weiterem Überschuß. Man würde die jeweiligen &lt;br /&gt;
ctrlBatSocManagementXX-&amp;gt;lcSlot Schlüssel definieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement01 lcSlot=23:00-23:10&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement02 lcSlot=00:00-23:59&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement03 lcSlot=00:00-23:59&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Wie ist der Ablauf: Die Batterie 1 unterliegt keiner Steuerung (nur von 23:00 bis 23:10 als Dummy-Periode). Das Reading Battery_ChargeUnrestricted_01 wird &amp;quot;1&amp;quot; gesetzt, d.h. die Batterie 1 wird zur Ladung uneingeschränkt freigegeben. Die anderen Batterien unterliegen der Steuerung -&amp;gt; Battery_ChargeUnrestricted_02 / 03 sind &amp;quot;0&amp;quot; und sollen nur geladen werden falls ein gesetztes Einspeiselimit überschritten wird.&lt;br /&gt;
&lt;br /&gt;
Ist das Ladeziel der Batterie 1 erreicht, setzt man um die Batterie 2 vollzuladen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement01 lcSlot=00:00-23:59&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement02 lcSlot=23:00-23:10&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement03 lcSlot=00:00-23:59&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Batterien 1 und 3 unterliegen der Steuerung, d.h. Battery_ChargeUnrestricted_01 / 03 haben den Wert &amp;quot;0&amp;quot;. Demgegenüber ist Battery_ChargeUnrestricted_02=1 und soll uneingeschränkt geladen werden.&lt;br /&gt;
&lt;br /&gt;
Ist auch die Batterie 2 voll geladen, würde man das Laden der Batterie 3 aktivieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement01 lcSlot=00:00-23:59&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement02 lcSlot=00:00-23:59&lt;br /&gt;
set ... attrKeyVal ctrlBatSocManagement03 lcSlot=23:00-23:10&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Setzens via &#039;&#039;&#039;attrKeyVal&#039;&#039;&#039; hat den Vorteil, dass die Zeitfenster-Syntax (Anfangszeit kleiner Endezeit usw.) im Hintergrund peprüft und ggf. ein Fehler zurückgegeben wird, den der Nutzer in seinem Script auswerten kann. Weiterhin werden die Attribute implizit gespeichert sofern global-&amp;gt;autosave nicht explizit auf &amp;quot;0&amp;quot; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Unterstützung eines netzdienlichen Verhaltens ====&lt;br /&gt;
&lt;br /&gt;
Der Steuerungsprozess der Batterieanlage leistet insgesamt einen kleinen Beitrag zur Netzstabilität, indem die Speicherladung in den Zeitraum der meisten prognostizierten Überschußeinspeisung gelegt wird. Im Sommer kann sich dieser Zeitraum in die Zeit nach dem Maxmimum des prognostizierten PV-Überschusses verlagern, wenn auch danach noch genügend Überschußenergie zu Volladung der Batterie prognostiziert wird. In dem Zusammenhang sollte im Attribut &#039;&#039;&#039;plantControl-&amp;gt;feedinPowerLimit&#039;&#039;&#039; ein Einspeiselimit gesetzt werden. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zur Verdeutlichung soll das Beispiel dienen:&lt;br /&gt;
&lt;br /&gt;
* die Batterie ist zu 60% geladen &lt;br /&gt;
* der User hat upSoC=40 eingestellt&lt;br /&gt;
* der User hat maxSoC=90 eingestellt&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Am Vormittag ist genügend Sonne vohanden, das Maximumum der Energie über die Zeit wird aber noch erwartet. &lt;br /&gt;
Zu diesem Zeitpunkt wird das Reading  &#039;&#039;&#039;Battery_ChargeUnrestricted_XX&#039;&#039;&#039; auf den Wert &amp;quot;0&amp;quot; gesetzt. Durch den Nutzer erfolgt daraufhin, zum Beipiel über ein Notify, ein anlagenspezifischer Befehl &amp;quot;Ladestop&amp;quot; an die Batterieanlage. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ab diesem Moment wird:&lt;br /&gt;
&lt;br /&gt;
# die Batterie nicht geladen&lt;br /&gt;
# die erzeugte PV-Energie dem Haushalt zur Verfügung gestellt bzw. der verbleibende Überschuß eingespeist, sofern der Überschuß unterhalb des im Attribut &#039;&#039;&#039;plantControl-&amp;gt;feedinPowerLimit&#039;&#039;&#039; definierten Limits liegt.&lt;br /&gt;
# ein eventuell über dem Limit &#039;&#039;&#039;plantControl-&amp;gt;feedinPowerLimit&#039;&#039;&#039; vorhandener Überschuß in die Batterie geladen und so die Netzlast verringert sowie die Batterie schonend geladen. (dieser Punkt trifft in den Monaten mit wenig PV-Erzeugung eher nicht zu)  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Gleichzeitig liefert die Batterie Energie an das Hausnetz und wird von 60% bis maximal einem SoC-Wert entladen, der durch die [[#Die_dynamische_SOC_Steuerung_mit_Umsetzungsbeispiel|dynamische SOC Steuerung]] bestimmt wird. Dazu muß diese Steuerung natürlich implementiert sein. Sofern der berechnete SoC größer als upSoC ist, wird der maximale Entladungs-SoC auf upSoC gesetzt. &lt;br /&gt;
&lt;br /&gt;
Zusätzlich überprüft das Modul permanent bei jedem Zyklus die Differenz des aktuell vorhandenen SoC zum eingestellten maxSoC.&lt;br /&gt;
Sie soll nicht größer sein um mit dem (noch) zu erwartenden PV-überschuß des Tages der eingestellte maxSoC bzw. dessen Nähe wahrscheinlich erreicht werden kann. &lt;br /&gt;
Sollte der Differenz-Grenzwert erreicht sein, wird &#039;&#039;&#039;Battery_ChargeUnrestricted_XX=1&#039;&#039;&#039; gesetzt und der Nutzer sollte dann über einen geeigneten Befehl seine Anlage in den Modus &amp;quot;Laden&amp;quot; umschalten.&lt;br /&gt;
Dieser Vorgang kann beliebig oft während des Tages alternieren.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Nutzung von batteryTrigger ===&lt;br /&gt;
Ergänzt werden die Möglichkeiten durch das set-Kommando: &lt;br /&gt;
&lt;br /&gt;
 batteryTrigger &amp;lt;1on&amp;gt;=&amp;lt;Wert&amp;gt; &amp;lt;1off&amp;gt;=&amp;lt;Wert&amp;gt; [&amp;lt;2on&amp;gt;=&amp;lt;Wert&amp;gt; &amp;lt;2off&amp;gt;=&amp;lt;Wert&amp;gt; ...] &lt;br /&gt;
&lt;br /&gt;
Das Kommando setzt Triggerpunkte bei Über- bzw. Unterschreitung bestimmter Batterieladungswerte (SoC in %).&lt;br /&gt;
&lt;br /&gt;
Der verwendete SoC wird als resultierender SoC als Summe der aktuellen Ladung aller registrierten Batterie-Geräte im Verhältnis zur installierten Gesamtkapazität gebildet. Das bedeutet, dass alle einzelnen Batterie-Geräte als ein gemeinsamer Cluster betrachtet werden. &lt;br /&gt;
&lt;br /&gt;
Es kann eine beliebige Anzahl von Triggerbedingungen angegeben werden. Xon/Xoff-Bedingungen müssen nicht zwingend paarweise definiert werden.&lt;br /&gt;
Überschreiten die letzten drei SoC-Messungen eine definierte Xon-Bedingung, wird das Reading &#039;&#039;&#039;batteryTrigger_X = on&#039;&#039;&#039; erstellt/gesetzt.&lt;br /&gt;
Unterschreiten die letzten drei SoC-Messungen eine definierte Xoff-Bedingung, wird das Reading &#039;&#039;&#039;batteryTrigger_X = off&#039;&#039;&#039; erstellt/gesetzt.&lt;br /&gt;
&lt;br /&gt;
Der Inhalt der Readings kann durch ein User-Programm oder, bei Erzeugung von entsprechenden Events, mittels notify-Device ausgewertet werden um bei Eintreten eines definierten Ereignisses entsprechende Reaktionen auszulösen. Das kann zum Beispiel die Freigabe eines Heizstabes oberhalb eines bestimmten SOC sein oder ein Entladeverbot der Batterie unterhalb eines SOC-Wertes um Reserven für einen eventuellen Stromausfall zu behalten.&lt;br /&gt;
&lt;br /&gt;
Damit die Batterietrigger dynamisch geändert werden können, ist die Einstellung als Set-Kommando und nicht als Attribut ausgeführt.   &lt;br /&gt;
&lt;br /&gt;
Alle Triggerpunkte können mit dem set-Befehl:&lt;br /&gt;
&lt;br /&gt;
 reset batteryTriggerSet&lt;br /&gt;
&lt;br /&gt;
wieder gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
== Verbrauchersteuerung - Registrieren und visualisieren von Verbrauchern ==&lt;br /&gt;
&lt;br /&gt;
Das Modul gestattet es beliebige Verbraucher (Devices) über die Attribute &#039;&#039;&#039;consumerXX&#039;&#039;&#039; zu registrieren. Durch die Registrierung wird dem Modul der Namen des Devices sowie dessen Eingenschaften durch die Angabe von Schlüssel-Wert Paaren bekannt gemacht.&lt;br /&gt;
&lt;br /&gt;
Nach der Registrierung können die Verbraucher durch das Modul genutzt werden:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* es erfolgt eine Planung der Ein- und Ausschaltzeiten abhängig von der solaren Prognose in Bezug zu den Leistungsdaten des Verbrauchers sowie der anderen registrierten Consumer&lt;br /&gt;
* das Modul kann die Ein- und Ausschaltsteuerung der Consumer übernehmen (optional)&lt;br /&gt;
* die aktuellen Status (Verbrauchsdaten) werden in der Energiefußgrafik dargestellt&lt;br /&gt;
* das Modul lernt mit der Zeit das Verbrauchsverhalten der registrierten Verbraucher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen Verbaucher zu registrieren, wird ein freies &#039;&#039;&#039;consumerXX&#039;&#039;&#039; Attribut, zum Beispiel consumer01, gesetzt.&lt;br /&gt;
&lt;br /&gt;
Die Eigenschaften und das Schaltverhalten wird durch die Angabe der verfügbaren Schlüssel gesteuert. Die Möglichkeiten sind sehr umfangreich. Die nachfolgenden Abschnitte beschreiben die Verwendung am Beispiel oft vorkommender bzw. nachgefragter Sachverhalte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Die Phasen der Verbrauchersteuerung ===&lt;br /&gt;
&lt;br /&gt;
Jeder Zyklus eines Verbrauchers durchläuft im Modul die folgenden Phasen:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Planung&#039;&#039;&#039; der Aktivzeiten des Verbrauchers, d.h. wann der Verbraucher geplant eingeschaltet sowie geplant ausgeschaltet wird und damit der Zyklus beendet wird.&lt;br /&gt;
# &#039;&#039;&#039;Start&#039;&#039;&#039; des Zyklus, d.h. Einschalten des Verbrauchers entsprechend der Planungsdaten sofern weitere, in den Consumer-Schlüsseln definierbare Rahmenbedingungen das Einschalten nicht verhindern (z.B. kein oder zu wenig PV-Energieerzeugung / PV-Überschuss)&lt;br /&gt;
# &#039;&#039;&#039;Permanente Überprüfung von&#039;&#039;&#039; eventuell vorhandenen &#039;&#039;&#039;Interruptbedingungen&#039;&#039;&#039; die den Verbraucher temporär ausschalten und, sofern die Interruptbedingung nicht mehr vorliegt, den Verbraucher wieder einschalten und so den gestarteten Zyklus fortsetzen.&lt;br /&gt;
#  &#039;&#039;&#039;Beendigung&#039;&#039;&#039; der Zyklus. Die Beendigung erfolgt entweder (normalerweise) wenn die geplante Endezeit der Zyklus erreicht ist oder eine optionale Endebedingung erfüllt ist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Steuerung der Phasen ====&lt;br /&gt;
Der Ablauf der Phasen kann durch verschiedene Schlüssel-Wert Paare beeinflusst und gesteuert werden.&lt;br /&gt;
&lt;br /&gt;
Mit dem optionalen Schlüssel &#039;&#039;&#039;swoncond&#039;&#039;&#039; kann eine &#039;&#039;&#039;zusätzliche externe Bedingung&#039;&#039;&#039; definiert werden um den Einschaltvorgang des Consumers freizugeben. Ist die Bedingung (Regex) nicht erfüllt, erfolgt kein Einschalten des Verbrauchers auch wenn die sonstigen Voraussetzungen wie Zeitplanung, on-Schlüssel, auto-Mode und aktuelle PV-Leistung gegeben sind. Es erfolgt somit eine &#039;&#039;&#039;UND-Verknüpfung&#039;&#039;&#039; des Schlüssels swoncond mit den Planungsdaten und weiteren Einschaltbedingungen.&lt;br /&gt;
&lt;br /&gt;
Der optionale Schlüssel &#039;&#039;&#039;swoffcond&#039;&#039;&#039; definiert eine &#039;&#039;&#039;vorrangige Ausschaltbedingung&#039;&#039;&#039; (Regex). Sobald diese Bedingung erfüllt ist, wird der Consumer ausgeschaltet auch wenn die geplante Endezeit (consumerXX_planned_stop) noch nicht erreicht ist (&#039;&#039;&#039;ODER-Verknüpfung&#039;&#039;&#039;). Weitere Bedingungen wie off-Schlüssel und auto-Mode müssen zum automatischen Ausschalten erfüllt sein.&lt;br /&gt;
&lt;br /&gt;
Mit dem optionalen Schlüssel &#039;&#039;&#039;interruptable&#039;&#039;&#039; kann während der geplanten Einschaltzeit eine automatische Unterbrechung sowie Wiedereinschaltung des Verbrauchers vorgenommen werden. Der Verbraucher wird temporär ausgeschaltet (interrupted) und wieder eingeschaltet (continued) wenn die Interrupt-Bedingung nicht mehr vorliegt. Die verbleibende Laufzeit wird durch einen Interrupt nicht beeinflusst! &lt;br /&gt;
&lt;br /&gt;
Der Schlüssel &#039;&#039;&#039;power&#039;&#039;&#039; gibt die nominale Leistungsaufnahme des Verbrauchers gemäß seines Datenblattes an. Dieser Wert wird verwendet um die Schaltzeiten des Verbrauchers zu planen und das Schalten in Abhängigkeit des tatsächlichen PV-Überschusses zum Einplanungszeitpunkt zu steuern. Ist &#039;&#039;&#039;power=0&#039;&#039;&#039; gesetzt, wird der Verbraucher unabhängig von einem zum Zeitpunkt des Zyklus-Start eventuell nicht ausreichend vorhandenem PV-Überschuss wie geplant eingeschaltet und somit der Zyklus gestartet.&lt;br /&gt;
&lt;br /&gt;
Durch die Schlüssel &#039;&#039;&#039;notbefore&#039;&#039;&#039; und &#039;&#039;&#039;notafter&#039;&#039;&#039; kann der Startzeitpunkt des Verbrauchers so gesteuert werden, dass der Start des Zyklus nicht vor bzw. nach der angegebenen Zeit eingeplant wird. Diese Steuerung bezieht sich auf die &#039;&#039;Planung&#039;&#039;, d.h. der eigentliche Start des Verbrauchers kann sich unter Umständen durch vorhandene Rahmenbedingungen verzögern. &lt;br /&gt;
&lt;br /&gt;
Der Schlüssel &#039;&#039;&#039;mintime&#039;&#039;&#039; legt die geplanten Einschaltzeit, d.h. die Laufzeit des Zyklus fest. Der Name &#039;&#039;&#039;mintime&#039;&#039;&#039; ist nicht als MInimum-Zeit zu deuten, sondern beschreibt die angegebene Zeit in Minuten die der Zyklus dauern soll.&lt;br /&gt;
&lt;br /&gt;
Dieser Schlüssel ist optional, da sich die Standard-Laufzeit des Verbrauchers von dessen Typ abgeleitet wird. Diese Standard Laufzeiten sind:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|dryer&lt;br /&gt;
|90 Minuten&lt;br /&gt;
|-&lt;br /&gt;
|fridge&lt;br /&gt;
|1440 Minuten&lt;br /&gt;
|-&lt;br /&gt;
|bev&lt;br /&gt;
|600 Minuten&lt;br /&gt;
|-&lt;br /&gt;
|dehydrator&lt;br /&gt;
|600 Minuten&lt;br /&gt;
|-&lt;br /&gt;
|heatpump&lt;br /&gt;
|Sonderfall&lt;br /&gt;
&lt;br /&gt;
KI-Prognose (ab V2.0.0) beachten &lt;br /&gt;
|-&lt;br /&gt;
|dishwasher&lt;br /&gt;
|180 Minuten&lt;br /&gt;
|-&lt;br /&gt;
|washingmachine&lt;br /&gt;
|120 Minuten&lt;br /&gt;
|-&lt;br /&gt;
|heater&lt;br /&gt;
|240 Minuten&lt;br /&gt;
|-&lt;br /&gt;
|charger&lt;br /&gt;
|120 Minuten&lt;br /&gt;
|-&lt;br /&gt;
|other&lt;br /&gt;
|60 Minuten&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Automatiksteuerung der Verbraucher ===&lt;br /&gt;
&lt;br /&gt;
==== Was ist die Automatiksteuerung? ====&lt;br /&gt;
&lt;br /&gt;
Die Automatiksteuerung ist der zentrale Mechanismus, mit dem SolarForecast einen Verbraucher (Consumer) eigenständig anhand von PV-Überschuss, Planungsdaten und den konfigurierten Rahmenbedingungen (Zeitfenster, Sperrzeiten, Prioritäten etc.) ein- und ausschaltet. Sie ist die Voraussetzung dafür, dass ein Consumer überhaupt automatisch geschaltet werden kann.&lt;br /&gt;
&lt;br /&gt;
Ist die Automatik für einen Consumer &#039;&#039;&#039;deaktiviert&#039;&#039;&#039;, greift SF nicht in dessen Schaltzustand ein – der Consumer kann dann ausschließlich manuell (per Schalter am Gerät, per Set-Befehl, über eine andere Automatisierung etc.) bedient werden.&lt;br /&gt;
&lt;br /&gt;
Ist die Automatik &#039;&#039;&#039;aktiviert&#039;&#039;&#039;, übernimmt SolarForecast die Kontrolle über den Consumer im Rahmen der jeweiligen Planungs- und Überschusslogik (Modus &amp;lt;code&amp;gt;can&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;must&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;mustNot&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Konfiguration: das Attribut &amp;lt;code&amp;gt;consumerXX-&amp;gt;auto&amp;lt;/code&amp;gt; ==== &lt;br /&gt;
&lt;br /&gt;
Für jeden Consumer wird über das consumerspezifische Attribut-Element &amp;lt;code&amp;gt;consumerXX-&amp;gt;auto&amp;lt;/code&amp;gt; festgelegt, &#039;&#039;&#039;welches Reading&#039;&#039;&#039; des Consumer-Devices die Automatikfreigabe liefert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
auto=&amp;amp;lt;Readingname&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
auto=Automatik&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wirkung:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Das referenzierte Reading wird von SolarForecast bei jedem Zyklus ausgelesen.&lt;br /&gt;
* Wert &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (bzw. jeder als &amp;quot;wahr&amp;quot; interpretierbare Wert) → Automatik &#039;&#039;&#039;aktiv&#039;&#039;&#039;: SolarForecast darf den Consumer schalten.&lt;br /&gt;
* Wert &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; → Automatik &#039;&#039;&#039;inaktiv&#039;&#039;&#039;: SolarForecast plant zwar ggf. weiter im Hintergrund, führt aber &#039;&#039;&#039;keine Schaltbefehle&#039;&#039;&#039; aus.&lt;br /&gt;
* Ist kein &amp;lt;code&amp;gt;auto&amp;lt;/code&amp;gt;-Schlüssel gesetzt, verhält sich der Consumer standardmäßig so, als wäre die Automatik dauerhaft aktiv (Default &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Zusammenspiel von Automatik-Reading und grafischem Schalter im Consumer-Panel ====&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2026-08-02 220921.png|right|thumb|400px|Automatik-Schalter im Consumer Panel]]&lt;br /&gt;
&lt;br /&gt;
Im Consumer-Panel (Bereich &amp;quot;Consumer Legend&amp;quot;) wird für jeden Consumer ein Schieberegler/Schalter für die Automatik angezeigt. Dieser Schalter ist &#039;&#039;&#039;keine eigenständige SolarForecast-interne Logik&#039;&#039;&#039;, sondern lediglich eine grafische Repräsentation des unter &amp;lt;code&amp;gt;auto&amp;lt;/code&amp;gt; hinterlegten Readings:&lt;br /&gt;
&lt;br /&gt;
* Betätigung des Schalters im Panel setzt den Wert des referenzierten Readings am zugeordneten Device auf 0 oder 1.&lt;br /&gt;
* SolarForecast liest ausschließlich dieses Reading aus – nicht den Schalterzustand selbst. Der Schalter ist also nur die Benutzeroberfläche für das Reading, keine separate Speicherstelle.&lt;br /&gt;
* Wird das Reading auf anderem Weg verändert (z.B. durch eine andere Automatisierung, ein Notify, etc.), zeigt der Panel-Schalter dies beim nächsten SolarForecast-Zyklus entsprechend an – die Wirkung auf SolarForecast ist identisch, unabhängig davon, auf welchem Weg das Reading gesetzt wurde.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Praktisch bedeutet das:&#039;&#039;&#039; Ob der Automatikmodus über den Panel-Schalter, ein Skript oder eine andere FHEM-Automatisierung umgeschaltet wird, spielt für SolarForecast keine Rolle – entscheidend ist ausschließlich der aktuelle Wert des konfigurierten Readings.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Manuelle Eingriffe während aktiver Automatik ====&lt;br /&gt;
&lt;br /&gt;
SolarForecast erkennt, wenn ein Consumer &#039;&#039;&#039;außerhalb der eigenen Schaltlogik&#039;&#039;&#039; geschaltet wird (z.B. per Schalter an der Steckdose, per App, durch eine andere Automatisierung), während die Automatik für diesen Consumer aktiv ist. Ein solcher externer Schaltvorgang wird im consumerXX-Reading mit dem Hinweis &amp;lt;code&amp;gt;von extern umgeschaltet&amp;lt;/code&amp;gt; protokolliert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Grundprinzip:&#039;&#039;&#039; SolarForecast unterbricht in diesem Fall bewusst seine eigene Schaltungslogik für diesen Consumer, um nicht störend in eine manuelle Aktion einzugreifen (z.B. laufende Wartung, kurzzeitiges Nachladen eines Wäschestücks in eine bereits laufende Waschmaschine, etc.).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Fall 1: Automatik wird aus- und wieder eingeschaltet ===== &lt;br /&gt;
&lt;br /&gt;
Wird die Automatik für einen Consumer &#039;&#039;&#039;bewusst deaktiviert und anschließend wieder aktiviert&#039;&#039;&#039; (Flanke AUS → EIN am &amp;lt;code&amp;gt;auto&amp;lt;/code&amp;gt;-Reading), so übernimmt SolarForecast die Kontrolle &#039;&#039;&#039;in jedem Fall wieder&#039;&#039;&#039; – unabhängig davon, ob der Schaltzustand des Consumers zwischenzeitlich manuell verändert wurde oder nicht, und unabhängig davon, ob dieser Zustand vor der Reaktivierung wiederhergestellt wurde.&lt;br /&gt;
&lt;br /&gt;
Dieser Vorgang wird im Consumer-Reading mit dem Hinweis &amp;lt;code&amp;gt;Automatik fortgesetzt&amp;lt;/code&amp;gt; quittiert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Merksatz:&#039;&#039;&#039; Die bewusste Reaktivierung der Automatik ist der eindeutigste Weg, die Kontrolle zuverlässig wieder an SF zu übergeben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Fall 2: Automatik bleibt durchgehend aktiv, Ursprungszustand wird wiederhergestellt ===== &lt;br /&gt;
&lt;br /&gt;
Bleibt die Automatik durchgehend &#039;&#039;&#039;aktiviert&#039;&#039;&#039; und der Consumer wird manuell geschaltet, erkennt SolarForecast automatisch, wenn der &#039;&#039;&#039;Schaltzustand vor der manuellen Aktion wiederhergestellt&#039;&#039;&#039; wird – also z.B.:&lt;br /&gt;
&lt;br /&gt;
* Consumer war automatisch ein → manuell aus → manuell wieder ein&lt;br /&gt;
* Consumer war automatisch aus → manuell ein → manuell wieder aus&lt;br /&gt;
&lt;br /&gt;
In diesem Fall übernimmt die Automatik ebenfalls wieder selbstständig, sobald der Ursprungszustand erreicht ist – auch ohne dass die Automatik zwischenzeitlich deaktiviert wurde. Auch dieser Vorgang wird mit &amp;lt;code&amp;gt;Automatik nach Rundlauf fortgesetzt&amp;lt;/code&amp;gt; quittiert.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig:&#039;&#039;&#039; Wird der Ursprungszustand &#039;&#039;&#039;nicht&#039;&#039;&#039; wiederhergestellt (z.B. Consumer war automatisch ein und wird manuell aus geschaltet, bleibt dann aber dauerhaft aus), bleibt der Consumer zunächst planungstechnisch &amp;quot;eingefroren&amp;quot; – siehe folgenden Abschnitt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Fall 3: Consumer bleibt manuell abweichend vom Automatikstatus stehen ===== &lt;br /&gt;
&lt;br /&gt;
Wird ein Consumer manuell geschaltet und der neue Zustand &#039;&#039;&#039;nicht&#039;&#039;&#039; wieder in den Ursprungszustand zurückgeführt (z.B. manuell dauerhaft ausgeschaltet, während die Automatik ihn eigentlich eingeschaltet lassen würde), bleibt der Consumer zunächst &#039;&#039;&#039;nicht&#039;&#039;&#039; unter aktiver Kontrolle der Automatik.&lt;br /&gt;
&lt;br /&gt;
Die Automatik übernimmt in diesem Fall &#039;&#039;&#039;trotzdem wieder&#039;&#039;&#039;, sobald sie den Consumer im Rahmen ihrer normalen Zyklen einmal selbst &amp;quot;berührt&amp;quot; – am häufigsten durch eine kurzzeitige Unterbrechung mangels ausreichendem PV-Überschuss. Sobald dieser interne Abgleich stattgefunden hat, ist der intern gespeicherte Schaltzustand wieder deckungsgleich mit dem tatsächlichen physischen Zustand, und die Automatik behandelt den Consumer ab diesem Zeitpunkt wieder vollständig regulär – inklusive automatischem Wiedereinschalten bei ausreichendem Überschuss.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Praktische Konsequenz:&#039;&#039;&#039; Bei Consumern mit häufig schwankendem Überschuss (typisch bei wechselhafter Bewölkung oder gleichzeitig aktiven anderen Verbrauchern) kann dieser interne Abgleich vergleichsweise schnell erfolgen – oft innerhalb weniger Minuten. Ein manuelles dauerhaftes Abschalten sollte deshalb &#039;&#039;&#039;nicht ausschließlich&#039;&#039;&#039; auf diesem impliziten Mechanismus beruhen, sondern nötigenfalls durch Deaktivieren der Automatik (siehe Fall 1) oder eine geeignete Ausschlussbedingung (z.B. &amp;lt;code&amp;gt;swoffcond&amp;lt;/code&amp;gt;) zuverlässig gegen ungewollten Wiederanlauf abgesichert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Best Practice ====&lt;br /&gt;
&lt;br /&gt;
Für ein zuverlässiges und nachvollziehbares Verhalten der Automatiksteuerung gilt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Kurzzeitige manuelle Eingriffe&#039;&#039;&#039; (z.B. kurz nachschauen, ein Wäschestück nachlegen) bei &#039;&#039;&#039;aktiver&#039;&#039;&#039; Automatik sind unproblematisch, solange der Ursprungszustand danach wiederhergestellt wird – die Automatik erkennt dies und läuft danach normal weiter.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Soll ein Consumer dauerhaft und zuverlässig von der Automatik ausgenommen werden&#039;&#039;&#039; (z.B. für längere Wartungsarbeiten, bewusstes Stilllegen), empfiehlt es sich, die Automatik für diesen Consumer &#039;&#039;&#039;explizit zu deaktivieren&#039;&#039;&#039; (&amp;lt;code&amp;gt;auto&amp;lt;/code&amp;gt;-Reading auf &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; setzen), statt sich auf einen dauerhaft abweichenden Schaltzustand zu verlassen. Nur so ist sichergestellt, dass SolarForecast in der Zwischenzeit keine Schaltbefehle ausführt.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Soll die Kontrolle anschließend zuverlässig wieder an SolarForecast übergeben werden&#039;&#039;&#039;, die Automatik bewusst wieder aktivieren (Flanke AUS → EIN). Dies ist der eindeutigste und sofortige Weg, unabhängig vom aktuellen Schaltzustand des Consumers.&lt;br /&gt;
&lt;br /&gt;
* Für Consumer, die &#039;&#039;&#039;dauerhaft manuell abweichend&#039;&#039;&#039; von der Automatik-Empfehlung bleiben sollen, obwohl die Automatik selbst aktiv bleibt, empfiehlt sich zusätzlich eine passende &amp;lt;code&amp;gt;swoffcond&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;swoncond&amp;lt;/code&amp;gt;-Bedingung, um ein unbeabsichtigtes Wiedereinschalten durch den in Fall 3 beschriebenen impliziten Abgleich zuverlässig zu verhindern.&lt;br /&gt;
&lt;br /&gt;
* Der Status jedes Schaltvorgangs (inkl. &amp;quot;extern umgeschaltet&amp;quot;- und &amp;quot;Rundlauf fortgesetzt&amp;quot;-Hinweise) ist jederzeit im jeweiligen &amp;lt;code&amp;gt;consumer&amp;amp;lt;XX&amp;amp;gt;&amp;lt;/code&amp;gt;-Reading im Feld &amp;lt;code&amp;gt;info=&amp;lt;/code&amp;gt; nachvollziehbar.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Der Verbraucher wurde nicht gestartet obwohl die Startzeit der Einplanung erreicht wurde ===&lt;br /&gt;
&lt;br /&gt;
Wenn die Startzeit des Consumers entsprechend der Einplanung erreicht oder überschritten ist, wird der Consumer eingeschaltet wenn die weiteren Voraussetzungen wahr sind:&lt;br /&gt;
&lt;br /&gt;
* es ist aktuell ein PV-Überschuss vorhanden und der PV-Überschuss deckt die kalkulierten Leistungsaufnahme des Verbrauchers ab. Mit den Schlüsseln &#039;&#039;&#039;power&#039;&#039;&#039; und &#039;&#039;&#039;spignorecond&#039;&#039;&#039; kann die Einschaltung trotz fehlendem PV-Überschuss ermöglicht werden. &lt;br /&gt;
&lt;br /&gt;
* die Angabe im Schlüssel &#039;&#039;&#039;swoncond&#039;&#039;&#039; ist wahr (sofern gesetzt)&lt;br /&gt;
&lt;br /&gt;
* das Schalten ist über den Schlüssel &#039;&#039;&#039;auto&#039;&#039;&#039; freigegeben (sofern gesetzt)&lt;br /&gt;
&lt;br /&gt;
* im Schlüssel &#039;&#039;&#039;on&#039;&#039;&#039; ist ein valides Einschaltkommando hinterlegt&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sind diese zusätzlichen Bedingungen nicht erfüllt, erfolgt kein Start des eingeplanten Zyklus. Der Verbraucher verbleibt in diesem Fall weiterhin im Status &#039;&#039;planned&#039;&#039; oder &#039;&#039;suspended&#039;&#039;. Die Startbedingungen werden regelmäßig reviewed und der Consumer gestartet sobald alle Startbedingungen wahr sind bzw. Start verhindernde Bedingungen entfallen sind. &lt;br /&gt;
&lt;br /&gt;
Dieser Vorgang erfolgt bis das geplante Ende des Verbaucherzyklus erreicht ist oder die Bedingung im Schlüssel &#039;&#039;&#039;swoffcond&#039;&#039;&#039; zutrifft. Sobald die Bedingung im Schlüssel &#039;&#039;&#039;swoffcond&#039;&#039;&#039; wahr ist, wird der gesamte Planungszyklus des Consumers beendet.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kann manuell / automatisiert in den Planungszyklus eines Verbrauchers eingegriffen werden? ===&lt;br /&gt;
&lt;br /&gt;
Die Einplanung und die darauf aufbauenden Schaltprozesse laufen gemäß den hinterlegten Schlüsseloptionen im Modul automatatisch ab ohne dass ein Eingriff durch den Anwender erfolgen muß.&lt;br /&gt;
&lt;br /&gt;
Dennoch kann es gewünscht sein eine Neuplanung oder eine Sofortplanung eines Consumers vorzunehmen weil der Bedarf dazu besteht. Zu diesem Zweck stehen die Set-Kommandos&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* consumerNewPlanning &lt;br /&gt;
&lt;br /&gt;
* consumerImmediatePlanning &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
zur Verfügung. &lt;br /&gt;
Beide Befehle initiieren die Consumer-Neuplanung, wobei mit dem Befehl &#039;&#039;consumerImmediatePlanning&#039;&#039; die eventuell im consumerXX Attribut gesetzten Schlüssel notbefore, notafter bzw. mode werden nicht beachtet werden. Dagenen beachtet der Befehl &#039;&#039;consumerNewPlanning&#039;&#039; alle definierten Schlüsseloptionen und dient gewöhnlich dazu einen abgeschlossenen Verbraucherzyklus wiederholt ausführen zu lassen weil die aktuelle Witterungslage dazu geeignet ist. &lt;br /&gt;
&lt;br /&gt;
Ein Anwendungsbeispiel dafür ist zum Beispiel die Ausführung von mehreren Waschmaschinen-Zyklen an einem langen, sonnigen Sommertag.&lt;br /&gt;
Diese beiden Set-Befehle können zum Beispiel über ein auf einen Schalter/Taster reagierendes Notify oder DOIF Device ausgeführt werden. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Registrierung eines Verbrauchers mit getrennten Geräten für Messung und Schalten ===&lt;br /&gt;
&lt;br /&gt;
Es existieren in FHEM Geräte, die über verschiedene Kanäle für unterschiedliche Aufgaben verfügen. Diese Kanäle werden jeweils in einem gesonderten Device abgebildet. HomeMatic oder readingsProxy sind Beispiele für solche Varianten.&lt;br /&gt;
&lt;br /&gt;
Um solche Verbraucher einzubinden gibt es im consumerXX Attribut den Schlüssel &#039;&#039;&#039;switchdev&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Bei der Registrierung gibt man als Consumerdevice das Gerät für die Messung an und im Schüssel switchdev das entsprechende FHEM-Device, welches für die Schaltvorgänge benutzt wird. &lt;br /&gt;
Ist switchdev angegeben, beziehen sich die weiteren Schlüssel on, off, swstate, auto und asynchron auf dieses Gerät.&lt;br /&gt;
&lt;br /&gt;
In dem nachfolgenden Beispiel (Homematic) ist &#039;&#039;eg.az.fridge_Pwr&#039;&#039; FHEM Device für die Energiemessung. Die Schlüssel &#039;&#039;pcurr&#039;&#039; und &#039;&#039;etotal&#039;&#039; geben Readings in diesem Device an damit SolarForecast den Verbrauch und die Energiemengen auslesen kann. Demgegenüber ist im Schlüssel &#039;&#039;switchdev&#039;&#039; das zugehörige Schalter-Device der Kombination angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
eg.az.fridge_Pwr&lt;br /&gt;
type=noSchedule switchdev=eg.az.fridge_Sw power=0 icon=fridge pcurr=power:W:5 etotal=energyCalc:Wh &lt;br /&gt;
swstate=state:on:off auto=automatic&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Registrierung von Verbrauchern ohne Zeitplanung und aktivem Schalten ===&lt;br /&gt;
Manchmal besteht der Wunsch, Verbraucher in SolarForecast zu integrieren um lediglich folgende Sachverhalte abzubilden:&lt;br /&gt;
&lt;br /&gt;
* Visualisierung des Schaltstatus in der Consumer Legende und/oder der Energieflußgrafik&lt;br /&gt;
* Darstellung des aktuellen Energieverbrauchs in der Energieflußgrafik&lt;br /&gt;
* Erfassung der (externen) Schaltzeiten, d.h. der Zeiten der Gerätenutzung sowie der Verbrauchsdaten um deren Einfluß bei den Planungszeiten anderer Geräte durch SolarForecast berücksichtigen zu lassen&lt;br /&gt;
&lt;br /&gt;
In solchen Fällen werden bei der Registrierung die Schlüssel &#039;&#039;swstate, pcurr&#039;&#039; und &#039;&#039;etotal&#039;&#039; zur Erfassung der Schaltzustände und der Energieverbrauchs angegeben, jedoch zur Verhinderung der Zeitplanung durch SolarForecast der Schlüssel &#039;&#039;&#039;type=noSchedule&#039;&#039;&#039; gesetzt sowie die Schlüssel &#039;&#039;on&#039;&#039; und &#039;&#039;off&#039;&#039; &#039;&#039;&#039;nicht&#039;&#039;&#039; gesetzt.&lt;br /&gt;
&lt;br /&gt;
Das nachfolgende Beispiel zeigt eine mögliche Registrierung eines Zwischensteckers (Shelly) zur Erfassung der Daten eines Gefrierschrankes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Shelly.shellyplug4&lt;br /&gt;
type=noSchedule power=65 asynchron=1&lt;br /&gt;
icon=gefrierschrank &lt;br /&gt;
swstate=state:.*on.*:.*off.* &lt;br /&gt;
pcurr=relay_0_power:W:5 etotal=relay_0_energy_Wh:Wh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Sonderregistrierung einer Wärmepumpe ===&lt;br /&gt;
&lt;br /&gt;
Das nachfolgende Beispiel zeigt die besondere Möglichkeit zur Registrierung (ab V2.0.0.) einer Wärmepumpe - aber nur wenn &#039;&#039;&#039;aiConActivate=1&#039;&#039;&#039; =&amp;gt; KI-Consumerprognose &amp;lt;== gesetzt und genutzt wird! &lt;br /&gt;
&lt;br /&gt;
Hinweis : Aktuell ist &amp;quot;nur&amp;quot; die Datensammlung für den &#039;opmode&#039; aktiv - noch keine CON-Betrachtung dieser Werte bis V2.8.1 -&amp;gt; 04-.07.2026)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EM_Waermepumpe &lt;br /&gt;
aliasshort=WP&lt;br /&gt;
type=heatpump&lt;br /&gt;
etotal=Bezug_Wirkleistung_Zaehler:kWh&lt;br /&gt;
icon=sani_heating_heatpump@orange &lt;br /&gt;
mode=mustNot&lt;br /&gt;
modulation=MQTT_EMSwp:boiler_data_heatingpumpmod&lt;br /&gt;
noshow=0&lt;br /&gt;
opmode=Forecast:user_wpmodus&lt;br /&gt;
pcurr=Bezug_Wirkleistung:W:100&lt;br /&gt;
power=3183&lt;br /&gt;
switchdev=MQTT_EMSwp   ### extra wg. swstate Reading auf MQTT_EMSwp&lt;br /&gt;
swstate=boiler_data_hpactivity:heating|cooling|hot.*|pool|poolheating|defrost:off&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erläuterungen zu diesen &#039;besondern&#039; Einträgen&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;heatpump&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|Für Wärmepumpen / Klimaanlagen etc.&lt;br /&gt;
Es aktiviert sich ein Feature-Set für Wärmepumpen. Dadurch ändern sich die Strukturen und das &#039;runConTrain&#039; muß erneuert gestartet werden.&lt;br /&gt;
In dem Status des Consumer-KI-Status-Popup ist auch erkennbar ob die Wärmepumpe erkannt wird und welches Featureset verwendet wird. Es sollte aber dann z.B. beim &#039;&#039;&amp;lt;nowiki/&amp;gt;&#039;attr aiControl aiConProfile=XYX&#039;&amp;lt;nowiki/&amp;gt;&#039;&#039; das Flag &#039;&#039;&#039;heatpump&#039;&#039;&amp;lt;nowiki/&amp;gt;&#039; zusätzlich gesetzt werden.&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;etotal&#039;&#039;&#039;&lt;br /&gt;
|der Schlüssel ist Pflichtangabe &lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;mode&#039;&#039;&#039;&lt;br /&gt;
|mustNot (Empfehlung bei modulierenden Gerätetypen)&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;Bei dem Verbrauchertyp &#039;&#039;&#039;heatpump&#039;&#039;&#039; ist sicherzustellen, dass keine doppelte Regelung durch SolarForecast und die native Gerätesteuerung erfolgt. Daher sollte bei modulierenden Verbrauchern dieses Types der Eintrag meist genutzt werden.&#039;&#039; &lt;br /&gt;
&#039;&#039;Ab V2.8.1 kann auch ein &amp;quot;can&amp;quot; oder &amp;quot;must&amp;quot; - wie bei allen anderen Verbrauchertypen - zur Einplanung / Steuerung durch Solarforecast genutzt  werden.&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;modulation&#039;&#039;&#039;&lt;br /&gt;
|Modulation des Aggregates in % (Pflichtangabe). Die mögliche Syntax ist: &lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;&amp;lt;Device&amp;gt;:&amp;lt;Reading&amp;gt;&#039;&#039;&#039; - Kombination welche die aktuelle Modulation (&#039;&#039;&#039;0..100&#039;&#039;&#039;) in % liefert &lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;100&#039;&#039;&#039; - feste Modulation von 100% für nichtmodulierende Geräte &lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;opmode&#039;&#039;&#039;&lt;br /&gt;
|definiert eine &amp;lt;Device&amp;gt;:&amp;lt;Reading&amp;gt; Kombination welche den aktuellen Betriebsmodus liefert (Pflichtangabe). &lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|Syntax: &#039;&#039;&#039;&amp;lt;Device&amp;gt;:&amp;lt;Reading&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|Die Rückgabe muß genau ein Wert der folgenden Auswahl sein: &#039;&#039;&#039;off heating defrost hotwater cooling pool poolheating&#039;&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;pcurr&#039;&#039;&#039;&lt;br /&gt;
|der Schlüssel ist Pflichtangabe - Maximale Leistungsaufnahme der Wärmepumpe / Klimaanlage etc. in W.&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;power&#039;&#039;&#039;&lt;br /&gt;
|maximale Leistungsaufnahme in W. Der Wert darf nicht! 0 sein. Der Schlüssel ist Pflichtangabe. &lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;swstate&#039;&#039;&#039;&lt;br /&gt;
|Schaltstatus des Kompressors. Die Syntax bleibt wie bei den anderen Consumern. &lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|Abweichend von anderen Consumern ist die Angabe verpflichtend, auch wenn der default verwendet werden soll.&lt;br /&gt;
Durch Erstellung eines passenden userReadings (WP-komplett / WP-Heizen / WP-Kühlen / WP-WW-Aufbereitung etc.) kann damit gesteuert werden, ob man sowohl Laufzeiten für Heiz- und Kühlbetrieb, Warmwassererzeugung und Heizstabbetrieb etc. in einem Consumer zusammenfassen will, oder ob man z.B. ausschließlich nur die Laufzeiten des Heiz- und Kühlbetriebs als aktive Zeiten für die Heizung (Kühlung) in dem jeweiligen consumerXX separat erfassen möchte.&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|Alle hier nicht angezogen Parameter sind wie in allen Verbrauchern zu nutzen &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Registrierung eines Shelly Devices ===&lt;br /&gt;
&lt;br /&gt;
Nachfolgendes Beispiel zeigt eine Registrierung eines Heizlüfters der an einem Shelly Zwischenstecker angeschlossen ist und durch das Modul gesteuert werden soll. Dabei soll die Steuerung nicht nur von der Solarprognose, sondern auch von der Raumtemperatur abhängig erfolgen. Im Beispiel wird das Attribut consumer03 verwendet.&lt;br /&gt;
&lt;br /&gt;
Zwingende Angaben sind&lt;br /&gt;
&lt;br /&gt;
 consumerXX &amp;lt;Device Name&amp;gt; type=&amp;lt;type&amp;gt; power=&amp;lt;power&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Alle Angaben können mehrzeilig eingegeben werden. Die Schlüssel-Werte Paare sind jeweils durch ein Leerzeichen getrennt.&lt;br /&gt;
&lt;br /&gt;
 consumerXX Shelly.shellyplug3 type=heater power=1700 &lt;br /&gt;
&lt;br /&gt;
In dem Beispiel ist Shelly.shellyplug3 der Devicename des Shellies in FHEM. Der Schlüssel &#039;&#039;&#039;type&#039;&#039;&#039; definiert die Art des Verbrauchers. In der Hilfe sind die möglichen Typen aufgeführt. Den richtigen Typ anzugeben hat Einfluß auf die spätere Einschätzung des Leistungsverhaltens über die Laufzeit. So wird von einem &#039;&#039;&#039;heater&#039;&#039;&#039; gleich nach dem Einschalten die angegebene Nominalleistung abgerufen und wird über die Zeit gleichbleiben. &lt;br /&gt;
Eine Waschmaschine oder ein Trockner rufen über ihre Laufzeit die Leistung nicht gleichbleibend ab und ändern die Leistungsaufnahme sich über die Einschaltdauer.&lt;br /&gt;
&lt;br /&gt;
Die Angabe von &#039;&#039;&#039;power&#039;&#039;&#039; definiert die Nominalleistung (Watt) die für den Verbraucher laut Typenschild vom Hersteller angegeben wird. Diese Angabe wird vom Modul bei der Planung der Einschaltzeiten verwendet indem die Nominalleistung in das Verhältnis zur Solarprognose bzw. Verbrauchsprognose des Netzes gesetzt wird. Weiterhin ist dieser Wert auch wichtig um später den tatsächlichen Einschaltzeitpunkt auszuführen wenn ein realer PV Überschuss festgestellt wird.&lt;br /&gt;
&lt;br /&gt;
Es ist möglich &#039;&#039;&#039;power=0&#039;&#039;&#039; zu setzen. Das führt dazu, dass die Planung und letztendlich auch der Schaltvorgang unabhängig von der Solarprognose bzw. einem realen PV Überschuss vorgenommen wird.  &lt;br /&gt;
&lt;br /&gt;
Es werden weitere Schlüsseleingaben vorgenommen:&lt;br /&gt;
&lt;br /&gt;
 Shelly.shellyplug3 type=heater power=1700 icon=vent_ventilation mode=can notbefore=09 mintime=SunPath:60:-60 on=on off=off&lt;br /&gt;
&lt;br /&gt;
Mit dem Schlüssel &#039;&#039;&#039;icon&#039;&#039;&#039; legt man ein Icon fest welches in der Grafik für den Verbraucher verwendet wird. Der &#039;&#039;&#039;mode&#039;&#039;&#039; definiert die Art und Weise der Einplanung:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;can: Die Einplanung erfolgt zum Zeitpunkt mit wahrscheinlich genügend verfügbaren PV Überschuss. Der Start des Verbrauchers zum Planungszeitpunkt unterbleibt bei ungenügendem PV-Überschuss.&lt;br /&gt;
&lt;br /&gt;
;must: Der Verbaucher wird optimiert eingeplant auch wenn wahrscheinlich nicht genügend PV Überschuss vorhanden sein wird. Der Start des Verbrauchers erfolgt auch bei ungenügendem PV-Überschuss.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;&#039;notbefore&#039;&#039;&#039; wird festgelegt, dass die Einplanung nicht vor neun Uhr morgens erfolgen soll auch falls schon genügend PV Überschuss vorhanden wäre. Der Schlüssel &#039;&#039;&#039;mintime&#039;&#039;&#039; definiert die Einplanungsdauer des Verbrauchers in Minuten im einfachsten Fall. Die hier verwendete Angabe &#039;&#039;&#039;SunPath&#039;&#039;&#039; ist ein Spezialfall. Der Verbraucher soll von Sonnenaufgang bis Sonnenuntergang eingeschaltet werden, wobei die Angabe von 60 bzw. -60 ein relative Verschiebung bewirken. Dadurch wird das Einschalten 60 Mintuen nach Sonnenaufgang bis 60 Minuten vor Sonnenuntergang geplant.&lt;br /&gt;
&lt;br /&gt;
Die Schlüssel &#039;&#039;&#039;on&#039;&#039;&#039; und &#039;&#039;&#039;off&#039;&#039;&#039; teilen dem Modul die jeweiligen gültigen Ein- und Aus-Kommandos mit, mit dem das (Shelly)Device geschaltet werden kann. Werden diese Schlüssel nicht oder &amp;quot;leer&amp;quot; (on= off=) angegeben, erfolgt kein Schalten durch das Modul, nur die Planungsdaten werden erzeugt.&lt;br /&gt;
&lt;br /&gt;
Die Verbraucherregistrierung wird mit weiteren Angaben ergänzt um das gewünschte Verhalten zu erreichen:&lt;br /&gt;
&lt;br /&gt;
 Shelly.shellyplug3 type=heater power=1700 icon=vent_ventilation mode=can notbefore=09 mintime=SunPath:60:-60 on=on off=off etotal=relay_0_energy_Wh:Wh  &lt;br /&gt;
 pcurr=relay_0_power:W auto=automatic interruptable=og.bad.wandthermostat:diff-temp:[0-9]\.[0-9]:0.2&lt;br /&gt;
&lt;br /&gt;
In &#039;&#039;&#039;etotal&#039;&#039;&#039; wird der Readingname des Shelly Devices angegeben welches die Summe der verbrauchten Energie (Wh/kWh) des Consumer Device liefert. D.h. es muß ein sich stetig erhöhender Wert sein. Durch die Auswertung dieses Readings ermittelt das Modul die in bestimmten Zeiteinheiten verbrauchte Energie zur weiteren Verwendung. &lt;br /&gt;
&lt;br /&gt;
In dem Shelly Device ist per default ein solches Reading nicht vorhanden. Über userReadings kann in dem Device Shelly.shellyplug3 ein Reading für etotal erzeugt werden:&lt;br /&gt;
&lt;br /&gt;
 userReadings relay_0_energy_Wh:relay_0_energy.* monotonic { sprintf &amp;quot;%.0f&amp;quot;, ReadingsVal ($name, &#039;relay_0_energy&#039;, 0) / 60 } &lt;br /&gt;
&lt;br /&gt;
Der Schlüssel &#039;&#039;&#039;pcurr&#039;&#039;&#039; enthält das Reading in Shelly.shellyplug3 welches den aktuellen Energieverbrauch liefert. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;auto&#039;&#039;&#039; enthält das Reading in Shelly.shellyplug3 welches zur Freigabe/Sperrung der autmatischen Schaltung durch das Modul dienen soll. Ist das angegebene Reading (im Beispiel &amp;quot;automatic&amp;quot;) im Shelly.shellyplug3 nicht vorhanden, wird es vom Modul automatisch mit dem Wert &amp;quot;1&amp;quot; angelegt.&lt;br /&gt;
Dadurch ist per default das automatische Schalten von Shelly.shellyplug3 durch das Modul freigegeben. &lt;br /&gt;
Der User kann durch Setzen des Readings &#039;&#039;&#039;automatic=0&#039;&#039;&#039; das automatische Schalten durch das Modul sperren und mit &amp;quot;1&amp;quot; wieder freigeben. Dadurch kann man zu bestimmten Zeiten (Urlaub, Feiertage, etc.) die Schaltung temporär deaktivieren.&lt;br /&gt;
&lt;br /&gt;
Wie oben beschrieben, soll der Heizlüfter als weitere Schaltbedingung die Abhängigkeit von der Raumtemperatur beachten. Konkret soll der Heizlüfter mit einer Hysterese von 0.2 (Grad) bei Erreichen einer Soll-Raumtemperatur ausschalten und bei Unterschreiten einer bestimmten Temperatur einschalten.&lt;br /&gt;
Der Schlüssel &#039;&#039;&#039;interruptable&#039;&#039;&#039; übernimmt diese temporäre Schaltsequenzen.&lt;br /&gt;
&lt;br /&gt;
Zunächst wird in dem Sensordevice (In dem Beispiel ein Homatic Wandthermostat HM-TC-IT-WM-W-EU) ein Reading erstellt welches dann im Schlüssel &#039;&#039;&#039;interruptable&#039;&#039;&#039; angegeben wird. Dieses Reading soll einen Wert enthalten auf den der angegebene Regex ([0-9]\.[0-9]) matchen soll um Shelly.shellyplug3 temporär auszuschalten.&lt;br /&gt;
Im Wandthermostat wird dazu ein userReading angelegt:&lt;br /&gt;
&lt;br /&gt;
 userReadings diff-temp:desired-temp.* { &lt;br /&gt;
     sprintf &amp;quot;%.1f&amp;quot;, ReadingsVal ($name, &#039;measured-temp&#039;, 0) - ReadingsVal ($name, &#039;desired-temp&#039;, 0) &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das bedeutet, wenn die Raumtemperatur die Solltemperatur erreicht oder höher ist, wird diff-temp &amp;gt;= 0.&lt;br /&gt;
In diesem Fall matcht der angebene Regex in:&lt;br /&gt;
&lt;br /&gt;
 interruptable=og.bad.wandthermostat:diff-temp:&#039;&#039;&#039;[0-9]\.[0-9]&#039;&#039;&#039;:0.2&lt;br /&gt;
&lt;br /&gt;
und Shelly.shellyplug3 wird ausgeschaltet. &lt;br /&gt;
Unterschreitet der Wert von diff-temp 0, matcht der Regex nicht mehr und der Verbraucher wird wieder eingeschaltet. Dabei wird die angegebene Hysterese berücksichtigt, d.h der Verbraucher wird erst ausgeschaltet wenn &amp;quot;diff-temp - 0.2 &amp;gt;= 0&amp;quot; wahr ist.&lt;br /&gt;
&lt;br /&gt;
Für das Wiedereinschalten des Heizlüfters ist außerdem Voraussetzung, dass ein entsprechender PV-Überschuss vorliegt. Diese Bedingung wird durch die Angabe von &#039;&#039;&#039;power=1700&#039;&#039;&#039; bewirkt. Soll der zwangsweise PV Überschuss ignoriert werden, kann &#039;&#039;&#039;power=0&#039;&#039;&#039; angegeben werden. Alternativ kann die Berücksichtigung des zwangsweisen PV Überschuss mit dem Schlüssel &amp;quot;spignorecond&amp;quot; im Consumer-Attribut ausgesteuert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== zusätzliche Readings bzw. Erzeugung von statistischen Readings ==&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zu den zahlreichen im Modul per Standard erzeugten Readings kann der Anwender weitere Readings generieren lassen.&lt;br /&gt;
Diese zusätzlichen Readings geben entweder einen bestimmten Sachverhalt (Laufzeit, Status der API-Abfragen, etc.) oder einen statistischen Wert, z.B. die Batterieentladung des aktuellen Tages, wieder.&lt;br /&gt;
&lt;br /&gt;
Die zusätzlich erstellten Readings sind durch den Präfix &#039;&#039;&#039;special_&#039;&#039;&#039; im Device gekennzeichnet.&lt;br /&gt;
&lt;br /&gt;
Diese zusätzlichen Informationen können durch das Setzen einer oder mehrerer Kennzeichen im Attribut &#039;&#039;&#039;ctrlSpecialReadings&#039;&#039;&#039; erzeugt werden. Die mögliche Auswahl wird je nach Bedarf ausgebaut und umfasst zum aktuellen Zeitpunkt (07.02.2025) diese Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;BatPowerIn_Sum: 	die Summe der momentanen Batterieladeleistung aller definierten Batterie Geräte&lt;br /&gt;
;BatPowerOut_Sum: 	die Summe der momentanen Batterieentladeleistung aller definierten Batterie Geräte&lt;br /&gt;
;allStringsFullfilled: 	Erfüllungsstatus der fehlerfreien Generierung aller Strings&lt;br /&gt;
;conForecastTillNextSunrise: 	Verbrauchsprognose von aktueller Stunde bis zum kommenden Sonnenaufgang&lt;br /&gt;
;currentAPIinterval: 	das aktuelle Abrufintervall der gewählten Strahlungsdaten-API in Sekunden&lt;br /&gt;
;currentRunMtsConsumer_XX: 	die Laufzeit (Minuten) des Verbrauchers &amp;quot;XX&amp;quot; seit dem letzten Einschalten. (letzter Laufzyklus)&lt;br /&gt;
;dayAfterTomorrowPVforecast: 	liefert die Vorhersage der PV Erzeugung für Übermorgen (sofern verfügbar) ohne Autokorrektur (Rohdaten).&lt;br /&gt;
;daysUntilBatteryCare_XX: 	Tage bis zur nächsten Batterie XX Pflege (Erreichen der Ladung &#039;maxSoC&#039; aus Attribut ctrlBatSocManagementXX)&lt;br /&gt;
;lastretrieval_time: 	der letzte Abrufzeitpunkt der gewählten Strahlungsdaten-API&lt;br /&gt;
;lastretrieval_timestamp: 	der Timestamp der letzen Abrufzeitpunkt der gewählten Strahlungsdaten-API&lt;br /&gt;
;response_message: 	die letzte Statusmeldung der gewählten Strahlungsdaten-API&lt;br /&gt;
;runTimeAvgDayConsumer_XX: 	die durchschnittliche Laufzeit (Minuten) des Verbrauchers &amp;quot;XX&amp;quot; an einem Tag&lt;br /&gt;
;runTimeCentralTask: 	die Laufzeit des letzten SolarForecast Intervalls (Gesamtprozess) in Sekunden&lt;br /&gt;
;runTimeTrainAI: 	die Laufzeit des letzten KI Trainingszyklus in Sekunden&lt;br /&gt;
;runTimeLastAPIAnswer: 	die letzte Antwortzeit des Strahlungsdaten-API Abrufs auf einen Request in Sekunden&lt;br /&gt;
;runTimeLastAPIProc: 	die letzte Prozesszeit zur Verarbeitung der empfangenen Strahlungsdaten-API Daten&lt;br /&gt;
;SunMinutes_Remain: 	die verbleibenden Minuten bis Sonnenuntergang des aktuellen Tages&lt;br /&gt;
;SunHours_Remain: 	die verbleibenden Stunden bis Sonnenuntergang des aktuellen Tages&lt;br /&gt;
;todayConsumptionForecast: 	Verbrauchsprognose pro Stunde des aktuellen Tages (01-24)&lt;br /&gt;
;todayConForecastTillSunset: 	Verbrauchsprognose von aktueller Stunde bis Stunde vor Sonnenuntergang&lt;br /&gt;
;todayDoneAPIcalls: 	die Anzahl der am aktuellen Tag ausgeführten Strahlungsdaten-API Calls&lt;br /&gt;
;todayDoneAPIrequests: 	die Anzahl der am aktuellen Tag ausgeführten Strahlungsdaten-API Requests&lt;br /&gt;
;todayConsumption: 	der gesamte Energieverbrauch (Wh) des Hauses am aktuellen Tag&lt;br /&gt;
;todayGridConsumption: 	die aus dem öffentlichen Netz bezogene Energie am aktuellen Tag&lt;br /&gt;
;todayGridFeedIn: 	die in das öffentliche Netz eingespeiste PV Energie am aktuellen Tag&lt;br /&gt;
;todayMaxAPIcalls: 	die maximal mögliche Anzahl Strahlungsdaten-API Calls. Ein Call kann mehrere API Requests enthalten.&lt;br /&gt;
;todayRemainingAPIcalls: 	die Anzahl der am aktuellen Tag noch möglichen Strahlungsdaten-API Calls&lt;br /&gt;
;todayRemainingAPIrequests: 	die Anzahl der am aktuellen Tag noch möglichen Strahlungsdaten-API Requests&lt;br /&gt;
;todayBatIn_XX: 	die am aktuellen Tag in die Batterie XX geladene Energie&lt;br /&gt;
;todayBatInSum: 	Summe der am aktuellen Tag in alle Batterien geladene Energie&lt;br /&gt;
;todayBatOut_XX: 	die am aktuellen Tag aus der Batterie XX entnommene Energie&lt;br /&gt;
;todayBatOutSum: 	Summe der am aktuellen Tag aus allen Batterien entnommene Energie&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig:&#039;&#039;&#039; Manche Angaben sind im Setup des Moduls optional, d.h. sie müssen nicht zwingend beim Setup angegeben werden. Allerdings sind diese Angaben für die Erstellung eines zusätzlichen Readings unter Umständen Voraussetzung. Es empfiehlt sich deshalb bei Setup so viele Informationen wie möglich zu übermitteln.&lt;br /&gt;
&lt;br /&gt;
So ist zum Beispiel für die sinnvolle Erstellung der Informationen &#039;&#039;&#039;todayBatInSum&#039;&#039;&#039; und &#039;&#039;&#039;todayBatOutSum&#039;&#039;&#039; (Readings special_todayBatInSum und special_todayBatOutSum) das Vorhandensein der Schlüssel &#039;&#039;intotal&#039;&#039; und &#039;&#039;outtotal&#039;&#039; im Attribut setupBatteryDevXX notwendig (Beispiel):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr &amp;lt;Name&amp;gt; setupBatteryDev01 MQTT2_cerboGX_c0619ab34e08_battery &lt;br /&gt;
                              pin=BatIn:W pout=BatOut:W charge=SOC_value intotal=BatInTotal:Wh outtotal=BatOutTotal:Wh &lt;br /&gt;
                              cap=InstalledCapacity_Wh:Wh asynchron=1 show=1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hinweise zur Fehlersuche ==&lt;br /&gt;
Das Modul SolarForecast ist sehr komplex und es die verschiedensten Datenquellen ausgewertet, zusammengeführt und daraus Ergebnisse berechnet und/oder visualisiert. Wird etwas nicht wie erwartet durch das Modul geliefert, können die Ursachen vielfältig sein. Natürlich kann ein Fehler im Modulcode vorliegen, oftmals gibt es aber andere Ursachen.&lt;br /&gt;
&lt;br /&gt;
Die nachfolgenden Hinweise sollen Hilfe zur Selbsthilfe geben und sind eine Zusammenfassung von realen Fällen die mit dem beschriebenen Wegen und Verfahren gelöst wurden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Die erwartete erzeugte PV-Energie ist im Modul zu gering und wird im Balkendiagramm nicht angezeigt === &lt;br /&gt;
&lt;br /&gt;
Die erzeugte PV-Energie wird nicht richtig angezeigt: Am Vormittag sind keine Werte vorhanden und, wenn dann etwas kommt, ist die Anzeige zu gering. Für 13 und 14 Uhr wurden ca. 5.000Wh erwartet (im Vergleich mit den Daten aus einer anderen Auswertungsquelle). &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lösungsweg:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Aus dem List des Devices wurden die für den Fall wesentlichen Readings herausgezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    2025-02-02 08:59:55  Today_Hour09_PVforecast 152 Wh&lt;br /&gt;
    2025-02-02 08:59:55  Today_Hour09_PVreal 0 Wh&lt;br /&gt;
&lt;br /&gt;
    2025-02-02 09:59:55  Today_Hour10_PVforecast 1400 Wh&lt;br /&gt;
    2025-02-02 09:59:55  Today_Hour10_PVreal 0 Wh&lt;br /&gt;
&lt;br /&gt;
    2025-02-02 10:59:55  Today_Hour11_PVforecast 2500 Wh&lt;br /&gt;
    2025-02-02 10:59:55  Today_Hour11_PVreal 0 Wh&lt;br /&gt;
&lt;br /&gt;
    2025-02-02 11:59:55  Today_Hour12_PVforecast 4392 Wh&lt;br /&gt;
    2025-02-02 11:59:55  Today_Hour12_PVreal 0 Wh&lt;br /&gt;
&lt;br /&gt;
    2025-02-02 12:59:54  Today_Hour13_PVforecast 4000 Wh&lt;br /&gt;
    2025-02-02 12:59:54  Today_Hour13_PVreal 300 Wh&lt;br /&gt;
&lt;br /&gt;
    2025-02-02 13:59:54  Today_Hour14_PVforecast 6415 Wh&lt;br /&gt;
    2025-02-02 13:59:54  Today_Hour14_PVreal 3200 Wh&lt;br /&gt;
&lt;br /&gt;
    2025-02-02 14:59:54  Today_Hour15_PVforecast 5629 Wh&lt;br /&gt;
    2025-02-02 14:59:54  Today_Hour15_PVreal 2700 Wh&lt;br /&gt;
&lt;br /&gt;
    2025-02-02 15:59:54  Today_Hour16_PVforecast 3958 Wh&lt;br /&gt;
    2025-02-02 15:59:54  Today_Hour16_PVreal 900 Wh&lt;br /&gt;
&lt;br /&gt;
    2025-02-02 16:31:24  Today_Hour17_PVforecast 945 Wh&lt;br /&gt;
    2025-02-02 16:31:24  Today_Hour17_PVreal 500 Wh&lt;br /&gt;
   &lt;br /&gt;
    2025-02-02 16:31:24  Today_Hour18_PVforecast 59 Wh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man sieht dass bis 12:00 keine erzeugte Energie vom WR gemeldet wird. Deswegen wird in der Balkengrafik nichts dargestellt. Auch danach bleibt die registrierte PV-Energie hinter den Erwartungen zurück. Zuständig für die Lieferung der PV-Energie an das Modul ist das Reading im Schlüssel:&lt;br /&gt;
&lt;br /&gt;
 setupInverterDev01 SH10rt pv=Total_DC_Power:W &amp;lt;mark&amp;gt;etotal=Total_Export_Energy_from_PV:kWh&amp;lt;/mark&amp;gt; capacity=10000 strings=Hauptdach,Flachdach&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Welche Änderungen es zwischen den Stunden gab, sieht man mit einem &amp;quot;get ... pvHistory XX&amp;quot; (&amp;quot;XX&amp;quot; steht für das Datum, d.h. den Tag, z.B. 02). &amp;lt;br&amp;gt;&lt;br /&gt;
Hier ein Beispiel für die Stunden 10 (9:00 - 9:59) und 11 (10:00 - 10:59). &amp;lt;br&amp;gt;&lt;br /&gt;
Wichtig ist hier der Key etotali01 für den ersten Inverter. Die Differenz zwischen den Werten beider Stunden ist die in der Stunde erzeugte Energie (hier 380 Wh). Diese 380 Wh findest du auch im Key pvrl01 als PVReal für diese Stunde. Das Modul rechnet intern immer mit Wh, kWh werden vorher in Wh umgerechnet.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
10 =&amp;gt; pvfc: 365, pvrl: 530, pvrlvd: 1, rad1h: -&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;mark&amp;gt;etotali01: 63364714&amp;lt;/mark&amp;gt;, etotali02: 3044110, etotali03: -&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;mark&amp;gt;pvrl01: 380&amp;lt;/mark&amp;gt;, pvrl02: 150, pvrl03: -&lt;br /&gt;
&lt;br /&gt;
            etotalp01: -, etotalp02: -, etotalp03: -&lt;br /&gt;
&lt;br /&gt;
            pprl01: -, pprl02: -, pprl03: -&lt;br /&gt;
&lt;br /&gt;
            confc: 574, con: 518, gcons: 22, conprice: 0.2958&lt;br /&gt;
&lt;br /&gt;
            gfeedin: 1, feedprice: 0.1269&lt;br /&gt;
&lt;br /&gt;
            DoN: 1, sunaz: 137, sunalt: 12&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
&lt;br /&gt;
            &lt;br /&gt;
&lt;br /&gt;
      11 =&amp;gt; pvfc: 2966, pvrl: 1862, pvrlvd: 1, rad1h: -&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;mark&amp;gt;etotali01: 63365094&amp;lt;/mark&amp;gt;, etotali02: 3044260, etotali03: -&lt;br /&gt;
&lt;br /&gt;
            pvrl01: 1392, pvrl02: 470, pvrl03: -&lt;br /&gt;
&lt;br /&gt;
            etotalp01: -, etotalp02: -, etotalp03: -&lt;br /&gt;
&lt;br /&gt;
            pprl01: -, pprl02: -, pprl03: -&lt;br /&gt;
&lt;br /&gt;
            confc: 774, con: 609, gcons: 25, conprice: 0.2958&lt;br /&gt;
&lt;br /&gt;
            gfeedin: 4, feedprice: 0.1269&lt;br /&gt;
           &lt;br /&gt;
....&lt;br /&gt;
&lt;br /&gt;
D.h. wenn zwischen den beiden Stunden keine Differenzen zu finden sind, liegt es sehr wahrscheinlich am Input des Readings:&lt;br /&gt;
&lt;br /&gt;
 etotal=Total_Export_Energy_from_PV:kWh&lt;br /&gt;
&lt;br /&gt;
welches sich in den ersten Stunden nicht ändert und danach auch nur wenig.&lt;br /&gt;
&lt;br /&gt;
Man kann mit dem Attribut:&lt;br /&gt;
&lt;br /&gt;
 ctrlDebug=collectData&lt;br /&gt;
&lt;br /&gt;
die Datensammlung verfolgen (leider entstehen viele Daten im Log). Man sieht welche Werte von dem Inverter/Reading geliefert werden:&lt;br /&gt;
 &lt;br /&gt;
 ....&lt;br /&gt;
 2025.02.02 19:10:10.558 1: SolCast DEBUG&amp;gt; collect Inverter 01 data - device: STP_5000, delivery: default =&amp;gt;&lt;br /&gt;
 2025.02.02 19:10:10.558 1: SolCast DEBUG&amp;gt; pv: 0 W, &amp;lt;mark&amp;gt;etotal: 63378810 Wh&amp;lt;/mark&amp;gt;&lt;br /&gt;
 ....&lt;br /&gt;
&lt;br /&gt;
Dieser Wert muß bei PV Erzeugung kontinuierlich hochzählen. Wenn nicht, muss das angegebene Reading, d.h. die Quelle überprüft werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ergebnis der Prüfung:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Tatsächlich wurde ein Reading benutzt, das ungeeignet war: Statt &amp;quot;Total_PV_Generation&amp;quot; wurde &amp;quot;Total_export_energy_from_PV&amp;quot; genutzt. In diesem Reading wurde immer die in die Batterie gespeicherte Energie von der gesamten erzeugten Energie abgezogen. Daher war auch vormittags alles 0, da in dieser Periode alle PV-Energie in die Batterie geladen wurde bzw. in weiteren Stunden ein Anteil der dann bei dem PV-Erzeugungswert fehlte.&lt;br /&gt;
&lt;br /&gt;
Nachdem die Ursache beseitigt war, zeigt SolarForecast wieder die erwarteten PV-Erzeugungswerte an.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Ich beobachte Blockierungen in meinem FHEM - ist SolarForecast eventuell der Verursacher? === &lt;br /&gt;
&lt;br /&gt;
==== Übersicht ====&lt;br /&gt;
&lt;br /&gt;
Dieses Dokument beschreibt die systematische Vorgehensweise zur Analyse und Lokalisierung von Blockierungszuständen im Kontext von SolarForecast (SF). Es dient als allgemeine Handlungsanleitung, um Ursachen für Systemverzögerungen oder hängende Prozesse einzugrenzen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Grundprinzipien der SF-Architektur ==== &lt;br /&gt;
&lt;br /&gt;
Bevor mit der Analyse begonnen wird, sind folgende Architekturmerkmale von SF zu verstehen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Alle API-Abfragen sind non-blocking&#039;&#039;&#039; ausgeführt. SF selbst blockiert den FHEM-Interpreter durch API-Kommunikation grundsätzlich nicht.&lt;br /&gt;
* &#039;&#039;&#039;Geräteabfragen und Datensammlungen&#039;&#039;&#039; erfolgen ausschließlich durch das Auslesen von Readings – &#039;&#039;&#039;nicht&#039;&#039;&#039; durch direkte Geräteabfragen. Die direkte Gerätekommunikation ist Aufgabe der jeweiligen Gerätemodule.&lt;br /&gt;
* &#039;&#039;&#039;Schaltvorgänge von Verbrauchern&#039;&#039;&#039; (Consumer) können potenziell Blockierungen verursachen, wenn das zugehörige Gerätemodul beim Schalten auf ein Schaltergebnis wartet (blockierender Aufruf im Gerätemodul).&lt;br /&gt;
* &#039;&#039;&#039;SF schreibt in regelmäßigen Abständen&#039;&#039;&#039; modulinterne Datenstrukturen in das Filesystem. Ein fehlerhaftes oder langsames Filesystem kann daher eine Blockierungsquelle darstellen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schritt-für-Schritt-Analyse ==== &lt;br /&gt;
&lt;br /&gt;
===== Schritt 1: Meldungen im Log identifizieren und zuordnen ===== &lt;br /&gt;
&lt;br /&gt;
Beim Auftreten von Auffälligkeiten zunächst das FHEM-Log auf bekannte Meldungen prüfen und deren Herkunft bestimmen.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Beispielmeldung !! Herkunft !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Data cycle triggered, watch readings&amp;lt;/code&amp;gt; || Rückmeldung der SF-Zentralschleife (von get &amp;lt;SF-Device&amp;gt; data) || Normaler Abschluss eines SF-Zyklus – zu diesem Zeitpunkt ist die Verarbeitung vollständig abgeschlossen. Kein Hinweis auf eine SF-interne Blockierung.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SolCast DEBUG&amp;gt; AI FANN drift data type &#039;con&#039; successfully written to file: ./FHEM/FhemUtils/NeuralNet_SolarForecast_SolCast&amp;lt;/code&amp;gt; || Eine Log-Ausgabe mit aktiviertem Debug || Logausgaben von SF erfolgen IMMER mit Angabe des SF-Namens (hier &#039;SolCast&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;There are still path commands in the action queue&amp;lt;/code&amp;gt; || Nicht von SF stammende Rückmeldung || Hinweis auf eine Warteschlange in einem Gerätemodul. Ursache im jeweiligen Gerätemodul suchen, nicht in SF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Meldungen, die nicht von SF generiert werden, müssen beim Hersteller bzw. Maintainer des jeweiligen Gerätemoduls analysiert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Schritt 2: Laufzeit der SF-Zentralschleife messen ===== &lt;br /&gt;
&lt;br /&gt;
Um zu beurteilen, ob SF selbst verzögert läuft, das Special Reading &amp;lt;code&amp;gt;runTimeCentralTask&amp;lt;/code&amp;gt; aktivieren:&lt;br /&gt;
&lt;br /&gt;
 attr &amp;lt;SF-Device&amp;gt; ctrlSpecialReadings runTimeCentralTask&lt;br /&gt;
&lt;br /&gt;
Dieses Reading liefert die &#039;&#039;&#039;Gesamtlaufzeit eines SF-Schleifenzyklus&#039;&#039;&#039; inklusive aller enthaltenen Abfragen und Verarbeitungsschritte.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Typische Werte:&#039;&#039;&#039; 0,2 – 0,3 Sekunden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Schritt 3: Laufzeiten loggen und auswerten ===== &lt;br /&gt;
&lt;br /&gt;
Die Werte des Readings &amp;lt;code&amp;gt;special_runTimeCentralTask&amp;lt;/code&amp;gt; dauerhaft mitschreiben, um Ausreißer und zeitliche Muster zu erkennen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Logging:&#039;&#039;&#039; via FileLog oder DbLog&lt;br /&gt;
* &#039;&#039;&#039;Auswertung:&#039;&#039;&#039; via SVG-Plot oder DbRep&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Durch die zeitliche Auswertung lässt sich erkennen:&lt;br /&gt;
* &#039;&#039;&#039;ob&#039;&#039;&#039; Blockierungen auftreten&lt;br /&gt;
* &#039;&#039;&#039;wann&#039;&#039;&#039; sie auftreten (Uhrzeit, Regelmäßigkeit)&lt;br /&gt;
* &#039;&#039;&#039;im Zusammenhang womit&#039;&#039;&#039; sie auftreten (z. B. Consumer-Schaltvorgänge)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Schritt 4: Consumer-Schaltvorgänge als Ursache prüfen ===== &lt;br /&gt;
&lt;br /&gt;
Falls Verbraucher (Consumer) aktiv geschaltet werden, ist dies eine &#039;&#039;&#039;priorisierte Spur&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
* Identifizieren, welche Gerätemodule beim Schalten eines Consumers involviert sind.&lt;br /&gt;
* Prüfen, ob diese Module &#039;&#039;&#039;blockierend&#039;&#039;&#039; auf ein Schaltergebnis warten.&lt;br /&gt;
* Zeitliche Korrelation zwischen Schaltvorgängen und erhöhten &amp;lt;code&amp;gt;runTimeCentralTask&amp;lt;/code&amp;gt;-Werten im Log prüfen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Schritt 5: Filesystem prüfen ===== &lt;br /&gt;
&lt;br /&gt;
Falls keine Consumer-Schaltvorgänge als Ursache infrage kommen oder die Blockierungen unregelmäßig und zeitlich nicht korreliert auftreten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Filesystem-Gesundheit&#039;&#039;&#039; des Systems prüfen (z. B. SD-Karte bei Raspberry Pi, NFS-Mounts, volle Partitionen).&lt;br /&gt;
* SF schreibt regelmäßig Datenstrukturen auf das Filesystem. Latenzen oder Fehler dabei können SF-Zyklen verzögern.&lt;br /&gt;
* Systemlogs (&amp;lt;code&amp;gt;dmesg&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;syslog&amp;lt;/code&amp;gt;) auf I/O-Fehler oder -Warnungen prüfen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Zusammenfassung: Checkliste ==== &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! # !! Prüfpunkt !! Tool / Methode&lt;br /&gt;
|-&lt;br /&gt;
| 1 || Log-Meldungen SF-intern oder fremd? || FHEM Logfile&lt;br /&gt;
|-&lt;br /&gt;
| 2 || &amp;lt;code&amp;gt;runTimeCentralTask&amp;lt;/code&amp;gt; aktivieren || &amp;lt;code&amp;gt;ctrlSpecialReadings&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 3 || Laufzeiten loggen || FileLog / DbLog&lt;br /&gt;
|-&lt;br /&gt;
| 4 || Ausreißer zeitlich auswerten || SVG / DbRep&lt;br /&gt;
|-&lt;br /&gt;
| 5 || Korrelation mit Consumer-Schaltvorgängen? || Zeitvergleich im Log&lt;br /&gt;
|-&lt;br /&gt;
| 6 || Gerätemodul des Consumers auf blockierende Aufrufe prüfen || Modul-Doku / Maintainer&lt;br /&gt;
|-&lt;br /&gt;
| 7 || Filesystem auf Fehler / Latenz prüfen || &amp;lt;code&amp;gt;dmesg&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;df&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;iostat&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Hinweise ==== &lt;br /&gt;
&lt;br /&gt;
* SF ist &#039;&#039;&#039;nicht&#039;&#039;&#039; der unmittelbare Verursacher, wenn Fremdmodule blockierende Aufrufe ausführen.&lt;br /&gt;
* Die Analyse sollte immer mit dem &#039;&#039;&#039;Logging der Laufzeiten&#039;&#039;&#039; beginnen, da nur so eine fundierte Aussage über Zeitpunkt und Häufigkeit möglich ist.&lt;br /&gt;
* Bei Meldungen unbekannter Herkunft stets das verantwortliche Gerätemodul identifizieren, bevor SF-interne Ursachen untersucht werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Konfigurationsbeispiele ==&lt;br /&gt;
&lt;br /&gt;
=== Visualisierung solare Vorhersage und reale Erzeugung ===&lt;br /&gt;
&lt;br /&gt;
Zu Beginn jedes neuen Tages gegen 00:00 Uhr werden durch das SolarForecast Device Events für die initiale PV Prognose des kommenden Tages erstellt.&lt;br /&gt;
Der Readingteil dieser Events heißt&lt;br /&gt;
&lt;br /&gt;
 AllPVforecastsToEvent&lt;br /&gt;
&lt;br /&gt;
Die Uhrzeiten der Events sind so aufbereitet und können direkt geloggt werden um sie in einen SVG Plot zu integrieren.&lt;br /&gt;
Im SolarForecast Device ist dieses Reading nicht sichtbar, nur die Events werden erstellt.&lt;br /&gt;
&lt;br /&gt;
Die meteorologischen Bedingungen verändern sich über den Tag permanent. Je nach gewählter Strahlungsdatenquelle (eine API oder DWD Device) erfolgt eine mehr oder weniger dynamische Anpassung der Prognose an die sich verändernde Umwelt.&lt;br /&gt;
&lt;br /&gt;
Aktuelle Prognosedaten sowie die reale PV Erzeugung der vergangenen Stunde können über die Readings&lt;br /&gt;
&lt;br /&gt;
 LastHourPVforecast&lt;br /&gt;
 LastHourPVreal&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2024-10-20 134050.png|right|thumb|400px|Übersicht solare Vorhersage]]&lt;br /&gt;
geloggt werden. &lt;br /&gt;
&lt;br /&gt;
Werden alle drei Werte in einem SVG kombiniert, kann die Entwicklung der Prognose über den Tag und die Beziehung von Prognose zu realer PV Erzeugnung pro Stunde visualisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für das rechts abgebildete Beispiel des Plots aus einer Datenbank &amp;quot;LogDBShort&amp;quot; sieht das gplot-File wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2024-03-08 15:05:31&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;&amp;lt;TL&amp;gt;&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Wh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;Wh&amp;quot;&lt;br /&gt;
set yrange [0:7500]&lt;br /&gt;
set y2range [0:7500]&lt;br /&gt;
&lt;br /&gt;
#LogDBShort SolCast:LastHourPVforecast:::&lt;br /&gt;
#LogDBShort SolCast:LastHourPVreal:::&lt;br /&gt;
#LogDBShort SolCast:AllPVforecastsToEvent:::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;aktuelle PV Vorhersage&#039; ls l6fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;reale PV Erzeugung&#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;initiale PV Vorhersage&#039; ls l4 lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; In manchen Fällen werden die Vorhersagewerte im SVG-Plot nicht angezeigt wenn FileLog verwendet wird. Ein Setzen des Attribute &amp;quot;fixedrange=3days +1&amp;quot; im SVG löst das Problem. Die Definition des SVG-Devices:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define SVG_LogDBShort_SolCast SVG LogDBShort:SVG_LogDBShort_SolCast:HISTORY&lt;br /&gt;
attr SVG_LogDBShort_SolCast fixedrange 3days +1&lt;br /&gt;
attr SVG_LogDBShort_SolCast room Energie-&amp;gt;SolarPrognose&lt;br /&gt;
attr SVG_LogDBShort_SolCast sortby 2&lt;br /&gt;
attr SVG_LogDBShort_SolCast title &amp;quot;Übersicht solare Vorhersage&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Technisch bedingt werden an einem Tag X kurz nach 00:00 Uhr die am Vortag für den Tag X erzeugten Events aktualisiert. Diese Daten erzeugen in der Datenbank einen zweiten Satz an Daten mit dem gleichen Timestamp was für die Anzeige unvorteilhaft ist. &lt;br /&gt;
Um nur die aktualisierten Events von &#039;&#039;&#039;AllPVforecastsToEvent&#039;&#039;&#039; in der Datenbank zu erhalten, bietet sich ein DbRep-Device an. Die nachfolgende Vorschlagsdefinition kann per at-Device jeden Tag kurz vor Mitternacht (z.B. 23:57:10) ausgeführt werden. Es werden immer die in der Vergangenheit geschriebenen (veralteten) Daten aus der Datenbank gelöscht, doppelte Datesätze vermieden und immer die aktuellste initiale Prognose gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define Rep.Del.AllPVforecastsToEvent DbRep LogDBShort&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent alias Löschen Readings AllPVforecastsToEvent des Folgetages&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent comment ermöglicht dass die Readings AllPVforecastsToEvent am Folgetag wieder neu und aktuell geschrieben werden können&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent devStateIcon initialized:control_3dot_hor_s connected:10px-kreis-gelb .*disconnect:10px-kreis-rot .*done:10px-kreis-gruen&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent disable 0&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent event-on-update-reading state&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent icon edit_delete&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent room Datenbank-&amp;gt;Produktiv&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent showproctime 1&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent device TYPE=SolarForecast&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent timestamp_begin next_day_begin&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent timestamp_end current_month_end&lt;br /&gt;
attr Rep.Del.AllPVforecastsToEvent verbose 2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das angegebene DbLog-Device &#039;&#039;&#039;LogDBShort&#039;&#039;&#039; ist natürlich anzupassen.&lt;br /&gt;
&lt;br /&gt;
Das at-Device zum Starten der Datenbankbereinigung sieht folgendermaßen aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define At.Del.AllPVforecastsToEvent at *23:58:10 set Rep.Del.AllPVforecastsToEvent delEntries&lt;br /&gt;
attr At.Del.AllPVforecastsToEvent alias Start Löschen Readings AllPVforecastsToEventn LogDBShort&lt;br /&gt;
attr At.Del.AllPVforecastsToEvent icon clock&lt;br /&gt;
attr At.Del.AllPVforecastsToEvent room Datenbank-&amp;gt;Produktiv&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Natürlich sind auch hier die eigenen Devicenamen entsprechend anzupassen.&lt;br /&gt;
&lt;br /&gt;
Ab SolarForecast Version 1.51.7 kann die Eventerzeugung für bestimmte SVG Plot-Typen optimiert werden. &amp;lt;br&amp;gt; &lt;br /&gt;
Die Aktivierung dieser Optimierungen ist in der Online Hilfe zum Attribut &#039;&#039;&#039;plantControl-&amp;gt;genPVforecastsToEvent&#039;&#039;&#039; beschrieben. Bei Nutzung des Attributes plantControl-&amp;gt;genPVforecastsToEvent ist ebenfalls das Attribut &#039;&#039;&#039;event-on-update-reading=AllPVforecastsToEvent&#039;&#039;&#039; zu setzen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispielkonfiguration 1 ===&lt;br /&gt;
Dies ist eine Konfiguration mit &lt;br /&gt;
&lt;br /&gt;
SummenDummy für 2 BatterieWR (Namen : SBS25 / SBS25_2)&lt;br /&gt;
&lt;br /&gt;
SummenDummy für 3 PV-Wechselrichter (Namen : SB25 / SB30 / SB40)&lt;br /&gt;
&lt;br /&gt;
            mit verschiedenen InverterStrings / ModulDirection / ModulTiltAngle, ModulPeakString&lt;br /&gt;
&lt;br /&gt;
und auch mit den notwendigen zugehörigen anderen Modul-Konfigs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ACHTUNG:&#039;&#039;&#039; Zusätzlich enthalten ist bei dem Beispiel-Notify eine Sonderkonstellation für eine Brennstoffzelle &amp;quot;FCU&amp;quot; als weitere bzw. zusätzliche Stromerzeugungsquelle. Diese &amp;quot;FCU&amp;quot; wird dadurch mit in der Grafik mit deren Erzeugungsleistung Tag und Nacht in der Erzeugersumme (am Symbol = Sonne) berücksichtigt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;(ReadingsVal(&amp;quot;FCU&amp;quot;,&amp;quot;FCU-Strom-aktuelle-Leistung&amp;quot;,0)/1000)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== DWD ====&lt;br /&gt;
Bitte dabei diese DWD-Version aus dem [https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter Contrib] von DS_Starter dazu nutzen&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|55_DWD_OpenData.pm&lt;br /&gt;
|136.2 KB ​&lt;br /&gt;
|29260  &lt;br /&gt;
|DS_Starter&lt;br /&gt;
|55_DWD_OpenData: contrib 1.17.7&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
define DWD DWD_OpenData&lt;br /&gt;
attr DWD downloadTimeout 120&lt;br /&gt;
attr DWD comment Im DWD Wetterdevice verwendet Solarforecast : \&lt;br /&gt;
TTT,Neff,RR1c,ww,SunUp,SunRise,SunSet \&lt;br /&gt;
zusätzlich ist jedoch auch noch Rad1h notwendig \&lt;br /&gt;
wenn dieses DWD-Device als Strahlungsdevice genutzt wird.\&lt;br /&gt;
Die Station 10418 (Lüdenscheid) überträgt aktuell am 09.03.2025 (noch) Rad1h.\&lt;br /&gt;
attr DWD downloadTimeout 120&lt;br /&gt;
attr DWD forecastDays 7&lt;br /&gt;
attr DWD forecastProperties SunUp, SunRise, SunSet, Rad1h, R101, RR1c, TTT, Tx, Tn, Tg, DD, FX1, RR6c, R600, RRhc, Rh00, ww, wwd, Neff&lt;br /&gt;
attr DWD forecastRefresh 1&lt;br /&gt;
attr DWD forecastResolution 1&lt;br /&gt;
attr DWD forecastStation 10418&lt;br /&gt;
attr DWD forecastWW2Text 1&lt;br /&gt;
attr DWD group Umwelt&lt;br /&gt;
attr DWD icon rc_WEB&lt;br /&gt;
attr DWD room 021_DWD&lt;br /&gt;
attr DWD stateFormat Tomorrow Tmax fc1_Tx °C on fc1_date at fc_description  -(state fc_time)&lt;br /&gt;
attr DWD verbose 2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== InverterDummy ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod InverterDummy dummy&lt;br /&gt;
attr InverterDummy event-on-change-reading .*&lt;br /&gt;
attr InverterDummy group Energy Meter&lt;br /&gt;
attr InverterDummy icon measure_photovoltaic_inst@green&lt;br /&gt;
attr InverterDummy room 020_PV,Energie&lt;br /&gt;
attr InverterDummy stateFormat {sprintf(&amp;quot;current %9.3f kW    Today_PVforecast  %9.3f kWh      Today_PV %9.3f kWh      Total_PV %9.3f kWh&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;total_pac&amp;quot;,0)/1,\&lt;br /&gt;
ReadingsNum(&amp;quot;Forecast&amp;quot;,&amp;quot;Today_PVforecast&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;etoday&amp;quot;,0)/1,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;etotal&amp;quot;,0)/1,)}&lt;br /&gt;
attr InverterDummy verbose 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SMA_Energymeter ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod SMA_Energymeter SMAEM&lt;br /&gt;
attr SMA_Energymeter DbLogExclude state&lt;br /&gt;
attr SMA_Energymeter diffAccept 50&lt;br /&gt;
attr SMA_Energymeter disable 0&lt;br /&gt;
attr SMA_Energymeter disableSernoInReading 1&lt;br /&gt;
attr SMA_Energymeter event-on-update-reading state,Saldo_Wirkleistung,Bezug_Wirkleistung,Einspeisung_Wirkleistung,Bezug_Wirkleistung_Zaehler,Einspeisung_Wirkleistung_Zaehler&lt;br /&gt;
attr SMA_Energymeter feedinPrice 0.08&lt;br /&gt;
attr SMA_Energymeter group Energy Meter&lt;br /&gt;
attr SMA_Energymeter icon measure_power@green&lt;br /&gt;
attr SMA_Energymeter interval 15&lt;br /&gt;
attr SMA_Energymeter powerCost 0.25&lt;br /&gt;
attr SMA_Energymeter room 015_Zaehler,020_PV,Energie&lt;br /&gt;
attr SMA_Energymeter serialNumber XXXXXXXXXX&lt;br /&gt;
attr SMA_Energymeter stateFormat state W (IN -) P1: L1_Saldo_Wirkleistung P2: L2_Saldo_Wirkleistung P3:L3_Saldo_Wirkleistung&lt;br /&gt;
attr SMA_Energymeter verbose 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== BatteryDummy ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod BatteryDummy dummy&lt;br /&gt;
attr BatteryDummy DbLogExclude .*&lt;br /&gt;
attr BatteryDummy event-on-change-reading .*&lt;br /&gt;
attr BatteryDummy group Energy Meter&lt;br /&gt;
attr BatteryDummy icon batterie@green&lt;br /&gt;
attr BatteryDummy room 020_PV,Energie&lt;br /&gt;
attr BatteryDummy stateFormat {ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;total_pac&amp;quot;, undef).&amp;quot; kW &amp;quot;.\&lt;br /&gt;
&amp;quot; - total &amp;quot;.ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;bat_loadtotal&amp;quot;, undef).&amp;quot; kWh (-in)&amp;quot;.\&lt;br /&gt;
&amp;quot; - &amp;quot;.ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;bat_unloadtotal&amp;quot;, undef).&amp;quot; kWh (out)&amp;quot;.\&lt;br /&gt;
&amp;quot; - charged &amp;quot;.ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;chargestatus&amp;quot;, undef).&amp;quot; % &amp;quot;}&lt;br /&gt;
attr BatteryDummy userReadings total_pac, power_out, power_in, chargestatus, bat_rated_capacity, bat_loadtotal, bat_unloadtotal&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Berechnungs&amp;quot;-Notify der Werte für Batterie- und InverterDummy ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod N.PV.TotalConsumption.Dum.Energy notify SMA_Energymeter:Saldo_Wirkleistung:.* {\&lt;br /&gt;
 # Batterie-Bezug -Batterieentnahme\&lt;br /&gt;
fhem &amp;quot;setreading Dum.Energy BattLoadIn &amp;quot;.sprintf(&amp;quot;%.1f&amp;quot;,(ReadingsVal(&amp;quot;SBS25&amp;quot;,&amp;quot;power_out&amp;quot;,0)));;\&lt;br /&gt;
 # Batterie-Beladung Batterie mit Strom füllen\&lt;br /&gt;
fhem &amp;quot;setreading Dum.Energy BattLoadOut &amp;quot;.sprintf(&amp;quot;%.1f&amp;quot;,(ReadingsVal(&amp;quot;SBS25&amp;quot;,&amp;quot;power_in&amp;quot;,0)));;\&lt;br /&gt;
 # Batteriestatus\&lt;br /&gt;
fhem &amp;quot;setreading Dum.Energy BattStatusP &amp;quot;.sprintf(&amp;quot;%.1f&amp;quot;,(ReadingsVal(&amp;quot;SBS25&amp;quot;,&amp;quot;chargestatus&amp;quot;,0)));;\&lt;br /&gt;
 # Batterie-Bezug -Batterieentnahme_2\&lt;br /&gt;
fhem &amp;quot;setreading Dum.Energy BattLoadIn_2 &amp;quot;.sprintf(&amp;quot;%.1f&amp;quot;,(ReadingsVal(&amp;quot;SBS25_2&amp;quot;,&amp;quot;power_out&amp;quot;,0)));;\&lt;br /&gt;
 # Batterie-Beladung_2 Batterie mit Strom füllen\&lt;br /&gt;
fhem &amp;quot;setreading Dum.Energy BattLoadOut_2 &amp;quot;.sprintf(&amp;quot;%.1f&amp;quot;,(ReadingsVal(&amp;quot;SBS25_2&amp;quot;,&amp;quot;power_in&amp;quot;,0)));;\&lt;br /&gt;
 # Batteriestatus_2\&lt;br /&gt;
fhem &amp;quot;setreading Dum.Energy BattStatusP_2 &amp;quot;.sprintf(&amp;quot;%.1f&amp;quot;,(ReadingsVal(&amp;quot;SBS25_2&amp;quot;,&amp;quot;chargestatus&amp;quot;,0)));;\&lt;br /&gt;
 # Forecast Invertererzeugung InverterDummy \&lt;br /&gt;
fhem &amp;quot;setreading InverterDummy Today_PVforecast &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,(ReadingsNum(&amp;quot;Forecast&amp;quot;,&amp;quot;Today_PVforecast&amp;quot;,0)));;\&lt;br /&gt;
 # Invertererzeugung InverterDummy \&lt;br /&gt;
fhem &amp;quot;setreading InverterDummy etotal &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,(ReadingsNum(&amp;quot;SB25&amp;quot;,&amp;quot;etotal&amp;quot;,0))+(ReadingsNum(&amp;quot;SB30&amp;quot;,&amp;quot;etotal&amp;quot;,0))+(ReadingsNum(&amp;quot;SB40&amp;quot;,&amp;quot;etotal&amp;quot;,0)));;\&lt;br /&gt;
 # Invertererzeugung InverterDummy \&lt;br /&gt;
 #fhem &amp;quot;setreading InverterDummy total_pac &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,(ReadingsVal(&amp;quot;MB_USRW610_004&amp;quot;,&amp;quot;Power_Sum__W&amp;quot;,0)/1000)+(ReadingsNum(&amp;quot;SB25&amp;quot;,&amp;quot;total_pac&amp;quot;,0))+(ReadingsNum(&amp;quot;SB30&amp;quot;,&amp;quot;total_pac&amp;quot;,0))+(ReadingsNum(&amp;quot;SB40&amp;quot;,&amp;quot;total_pac&amp;quot;,0)));;\&lt;br /&gt;
fhem &amp;quot;setreading InverterDummy total_pac &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,(ReadingsNum(&amp;quot;SB25&amp;quot;,&amp;quot;total_pac&amp;quot;,0))+(ReadingsNum(&amp;quot;SB30&amp;quot;,&amp;quot;total_pac&amp;quot;,0))+(ReadingsNum(&amp;quot;SB40&amp;quot;,&amp;quot;total_pac&amp;quot;,0)));;\&lt;br /&gt;
#fhem &amp;quot;setreading InverterDummy total_pac &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,(ReadingsVal(&amp;quot;FCU&amp;quot;,&amp;quot;FCU-Strom-aktuelle-Leistung&amp;quot;,0)/1000)+(ReadingsNum(&amp;quot;SB25&amp;quot;,&amp;quot;total_pac&amp;quot;,0))+(ReadingsNum(&amp;quot;SB30&amp;quot;,&amp;quot;total_pac&amp;quot;,0))+(ReadingsNum(&amp;quot;SB40&amp;quot;,&amp;quot;total_pac&amp;quot;,0)));;\&lt;br /&gt;
 # Invertererzeugung InverterDummy \&lt;br /&gt;
my $wert1234 = &amp;quot;0&amp;quot; ;;\&lt;br /&gt;
$wert1234 = sprintf(&amp;quot;%.3f&amp;quot;,(ReadingsNum(&amp;quot;SB25&amp;quot;,&amp;quot;etoday&amp;quot;,0))+(ReadingsNum(&amp;quot;SB30&amp;quot;,&amp;quot;etoday&amp;quot;,0))+(ReadingsNum(&amp;quot;SB40&amp;quot;,&amp;quot;etoday&amp;quot;,0)));; \&lt;br /&gt;
fhem (&amp;quot;setreading InverterDummy etoday &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,$wert1234));;\&lt;br /&gt;
 # Batterie-Bezug -Batterieentnahme InverterDummy\&lt;br /&gt;
fhem &amp;quot;setreading BatteryDummy power_out &amp;quot;.sprintf(&amp;quot;%.0f&amp;quot;,(ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;power_out&amp;quot;,0))+(ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;power_out&amp;quot;,0)));;\&lt;br /&gt;
 # Batterie-Beladung InverterDummyBatterie mit Strom füllen\&lt;br /&gt;
fhem &amp;quot;setreading BatteryDummy power_in &amp;quot;.sprintf(&amp;quot;%.0f&amp;quot;,(ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;power_in&amp;quot;,0))+(ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;power_in&amp;quot;,0)));;\&lt;br /&gt;
 # Batterie-Bezug -bat_loadtotal Batterieentnahme InverterDummy\&lt;br /&gt;
fhem &amp;quot;setreading BatteryDummy bat_unloadtotal &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,(ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;bat_unloadtotal&amp;quot;,0))+(ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;bat_unloadtotal&amp;quot;,0)));;\&lt;br /&gt;
 # Batterie-Beladung bat_loadtotal InverterDummyBatterie mit Strom füllen\&lt;br /&gt;
fhem &amp;quot;setreading BatteryDummy bat_loadtotal &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,(ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;bat_loadtotal&amp;quot;,0))+(ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;bat_loadtotal&amp;quot;,0)));;\&lt;br /&gt;
 # Batteriestatus InverterDummy\&lt;br /&gt;
my $wert5 = sprintf(&amp;quot;%.2f&amp;quot;,(((ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;chargestatus&amp;quot;,0))/2) + ((ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;chargestatus&amp;quot;,0))/2)));; \&lt;br /&gt;
fhem (&amp;quot;setreading BatteryDummy chargestatus &amp;quot;.sprintf(&amp;quot;%.2f&amp;quot;,$wert5));;\&lt;br /&gt;
 # Batterie-total_pac  InverterDummy\&lt;br /&gt;
my $wert6 = sprintf(&amp;quot;%.3f&amp;quot;,((ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;total_pac&amp;quot;,0))+(ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;total_pac&amp;quot;,0))));; \&lt;br /&gt;
fhem (&amp;quot;setreading BatteryDummy total_pac &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,$wert6));;\&lt;br /&gt;
 # Batterie-total_pac  InverterDummy\&lt;br /&gt;
my $wert7 = sprintf(&amp;quot;%.3f&amp;quot;,((ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;bat_rated_capacity&amp;quot;,0))+(ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;bat_rated_capacity&amp;quot;,0))));; \&lt;br /&gt;
fhem (&amp;quot;setreading BatteryDummy bat_rated_capacity &amp;quot;.sprintf(&amp;quot;%.3f&amp;quot;,$wert7));;\&lt;br /&gt;
 # möglicher Aufruf einer Batterie-Bebladung-Routine....SMABatteryChargewithTibber();;\&lt;br /&gt;
}&lt;br /&gt;
attr N.PV.TotalConsumption.Dum.Energy DbLogExclude .*&lt;br /&gt;
attr N.PV.TotalConsumption.Dum.Energy room Energie&lt;br /&gt;
attr N.PV.TotalConsumption.Dum.Energy verbose 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SolarForecast ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Forecast SolarForecast&lt;br /&gt;
attr Forecast DbLogExclude .*&lt;br /&gt;
attr Forecast DbLogInclude Current_BatCharge999&lt;br /&gt;
attr Forecast affectBatteryPreferredCharge 30&lt;br /&gt;
attr Forecast affectConsForecastLastDays 31&lt;br /&gt;
attr Forecast affect70percentRule 0&lt;br /&gt;
attr Forecast comment &amp;quot;wget -qO ./FHEM/76_SolarForecast.pm https://svn.fhem.de/fhem/trunk/fhem/contrib/DS_Starter/76_SolarForecast.pm&amp;quot;\&lt;br /&gt;
&amp;quot;wget -qO ./FHEM/55_DWD_OpenData.pm https://svn.fhem.de/fhem/trunk/fhem/contrib/DS_Starter/55_DWD_OpenData.pm&amp;quot;\&lt;br /&gt;
&amp;quot;13.01.2025 mit der Version 76_SolarForecast.pm:v1.43.2-s29518/2025-01-12&amp;quot;&lt;br /&gt;
attr Forecast graphicHeaderOwnspec PV&amp;amp;nbsp;;Heute&amp;amp;nbsp;;real:Today_PVreal Verbrauch&amp;amp;nbsp;;bis&amp;amp;nbsp;;Sonnenaufgang&amp;amp;nbsp;;:special_conForecastTillNextSunrise PV&amp;amp;nbsp;;Morgen&amp;amp;nbsp;;erwartet:Tomorrow_PVforecast PV&amp;amp;nbsp;;Uebermorgen&amp;amp;nbsp;;erwartet:special_dayAfterTomorrowPVforecast  Batt.-Ladeanforderung&amp;amp;nbsp;;:Battery_ChargeRequest FCU-Erzeugung&amp;amp;nbsp;;:Current_PP01\&lt;br /&gt;
attr Forecast consumer01 FBDECT_fbahahttp_11657_0127183 icon=scene_washing_machine@orange type=washingmachine power=10 swstate:state notbefore=09 notafter=20 pcurr=power:W:3 etotal=energy:Wh interruptable=1 auto=solarforecast_auto surpmeth=default&lt;br /&gt;
attr Forecast consumer02 FBDECT_fbahahttp_E8_DF_70_07_3E_57 icon=light_floor_lamp@orange type=other power=15 swstate:state pcurr=power:W:10 etotal=energy:Wh interruptable=0 auto=solarforecast_auto surpmeth=default&lt;br /&gt;
attr Forecast consumer03 FBDECT_fbahahttp_E8_DF_70_07_42_0B icon=raspberrypi@orange type=other power=8 swstate:state pcurr=power:W:1 etotal=energy:Wh interruptable=0 auto=solarforecast_auto surpmeth=default&lt;br /&gt;
attr Forecast consumer04 FBDECT_fbahahttp_11657_0067275 icon=springbrunnen_icon@orange type=other power=50 swstate:state pcurr=power:W:10 etotal=energy:Wh interruptable=0 auto=solarforecast_auto surpmeth=default&lt;br /&gt;
attr Forecast consumer05 FBDECT_fbahahttp_34_31_C4_D4_31_37 icon=sani_domestic_waterworks@orange type=other power=10 swstate:state pcurr=power:W:3 etotal=energy:Wh auto=solarforecast_auto surpmeth=default&lt;br /&gt;
attr Forecast consumer06 tuya_local_bf5037060f450bdbd4rl0q icon=scene_clothes_dryer@orange type=dryer power=10 swstate:state pcurr=cur_power:W:3 etotal=energy:Wh auto=solarforecast_auto surpmeth=default&lt;br /&gt;
attr Forecast consumer07 tuya_local_bfac44fb487476efd1vhdu icon=weather_sunset@orange type=noSchedule power=5 swstate:state pcurr=cur_power:W:3 etotal=energy:Wh auto=solarforecast_auto surpmeth=default&lt;br /&gt;
attr Forecast consumerControl adviceIcon=light_light_dim_100@gold&lt;br /&gt;
attr Forecast consumerControl showLegend=icon_top&lt;br /&gt;
attr Forecast consumerControl detailLink=1&lt;br /&gt;
attr Forecast ctrlAIdataStorageDuration 1825&lt;br /&gt;
attr Forecast ctrlAIshiftTrainStart 2&lt;br /&gt;
attr Forecast ctrlBatSocManagement01 lowSoc=10 upSoC=30 maxSoC=99 careCycle=20&lt;br /&gt;
attr Forecast ctrlBatSocManagement02 lowSoc=10 upSoC=30 maxSoC=99 careCycle=20&lt;br /&gt;
attr Forecast ctrlDebug none&lt;br /&gt;
attr Forecast plantControl genPVdeviation=continuously&lt;br /&gt;
attr Forecast plantControl cycleInterval=15&lt;br /&gt;
attr Forecast ctrlNextDayForecastReadings 01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24&lt;br /&gt;
attr Forecast ctrlNextHoursSoCForecastReadings 00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23&lt;br /&gt;
attr Forecast ctrlSpecialReadings BatPowerIn_Sum,BatPowerOut_Sum,SunHours_Remain,SunMinutes_Remain,allStringsFullfilled,conForecastTillNextSunrise,currentAPIinterval,currentRunMtsConsumer_01,currentRunMtsConsumer_02,currentRunMtsConsumer_03,currentRunMtsConsumer_04,currentRunMtsConsumer_05,currentRunMtsConsumer_06,currentRunMtsConsumer_07,dayAfterTomorrowPVforecast,daysUntilBatteryCare_01,daysUntilBatteryCare_02,lastretrieval_time,lastretrieval_timestamp,response_message,runTimeAvgDayConsumer_01,runTimeAvgDayConsumer_02,runTimeAvgDayConsumer_03,runTimeAvgDayConsumer_04,runTimeAvgDayConsumer_05,runTimeAvgDayConsumer_06,runTimeAvgDayConsumer_07,runTimeCentralTask,runTimeLastAPIAnswer,runTimeLastAPIProc,runTimeTrainAI,todayBatIn_01,todayBatIn_02,todayBatOut_01,todayBatOut_02,todayConForecastTillSunset,todayConsumptionForecast,todayDoneAPIcalls,todayDoneAPIrequests,todayGridConsumption,todayGridFeedIn,todayMaxAPIcalls,todayRemainingAPIcalls,todayRemainingAPIrequests&lt;br /&gt;
attr Forecast disable 0&lt;br /&gt;
attr Forecast event-min-interval .*:1800&lt;br /&gt;
attr Forecast event-on-change-reading .*&lt;br /&gt;
attr Forecast flowGraphicControl animate=1 consumerdist=80 h2consumerdist=50 shiftx=0  shifty=0 showconsumer=1 showconsumerdummy=1 showconsumerpower=1 showconsumerremaintime=0 size=400 strokewidth=12&lt;br /&gt;
attr Forecast graphicBeam1Color 3C14FF&lt;br /&gt;
attr Forecast graphicBeam1Content pvReal&lt;br /&gt;
attr Forecast graphicBeam2Color 19FF29&lt;br /&gt;
attr Forecast graphicBeam2Content pvForecast&lt;br /&gt;
attr Forecast graphicBeam3Color D60924&lt;br /&gt;
attr Forecast graphicBeam3Content batsocforecast_02&lt;br /&gt;
attr Forecast graphicBeam3FontColor FFFF0D&lt;br /&gt;
attr Forecast graphicBeam4Color FFFF1F&lt;br /&gt;
attr Forecast graphicBeam4Content batsocforecast_01&lt;br /&gt;
attr Forecast graphicBeam4FontColor 000000&lt;br /&gt;
attr Forecast graphicBeamHeightLevel1 200&lt;br /&gt;
attr Forecast graphicBeamHeightLevel2 200&lt;br /&gt;
attr Forecast graphicHeaderDetail all&lt;br /&gt;
attr Forecast graphicHeaderOwnspec #PV\&lt;br /&gt;
PV&amp;amp;nbsp;;Heute&amp;amp;nbsp;;real:Today_PVreal\&lt;br /&gt;
PV&amp;amp;nbsp;;Morgen&amp;amp;nbsp;;erwartet:Tomorrow_PVforecast\&lt;br /&gt;
PV&amp;amp;nbsp;;Uebermorgen&amp;amp;nbsp;;erwartet:special_dayAfterTomorrowPVforecast\&lt;br /&gt;
:\&lt;br /&gt;
#\&lt;br /&gt;
AutarkyRate:Current_AutarkyRate\&lt;br /&gt;
Überschuss:Current_Surplus\&lt;br /&gt;
aktueller&amp;amp;nbsp;;Netzbezug:Current_GridConsumption\&lt;br /&gt;
:\&lt;br /&gt;
#Verbrauch\&lt;br /&gt;
bis&amp;amp;nbsp;;Sonnenuntergang:special_todayConForecastTillSunset\&lt;br /&gt;
bis&amp;amp;nbsp;;Sonnenaufgang&amp;amp;nbsp;;:special_conForecastTillNextSunrise\&lt;br /&gt;
:\&lt;br /&gt;
:\&lt;br /&gt;
#Batterie01\&lt;br /&gt;
Batt.-Ladeanforderung&amp;amp;nbsp;;:Battery_ChargeRequest_01\&lt;br /&gt;
Batt.-Ladung&amp;amp;nbsp;;empfohlen:Battery_ChargeUnrestricted_01\&lt;br /&gt;
Ladung&amp;amp;nbsp;;heute:special_todayBatIn_01\&lt;br /&gt;
Entladung&amp;amp;nbsp;;heute:special_todayBatOut_01\&lt;br /&gt;
#Batterie01_tmp\&lt;br /&gt;
Current_PowerBatIn_01:Current_PowerBatIn_01\&lt;br /&gt;
Current_PowerBatOut_01:Current_PowerBatOut_01\&lt;br /&gt;
:\&lt;br /&gt;
:\&lt;br /&gt;
#Batterie02\&lt;br /&gt;
Batt.-Ladeanforderung&amp;amp;nbsp;;:Battery_ChargeRequest_02\&lt;br /&gt;
Batt.-Ladung&amp;amp;nbsp;;empfohlen:Battery_ChargeUnrestricted_02\&lt;br /&gt;
Ladung&amp;amp;nbsp;;heute:special_todayBatIn_02\&lt;br /&gt;
Entladung&amp;amp;nbsp;;heute:special_todayBatOut_02\&lt;br /&gt;
#Batterie02_tmp\&lt;br /&gt;
Current_PowerBatIn_02:Current_PowerBatIn_02\&lt;br /&gt;
Current_PowerBatOut_02:Current_PowerBatOut_02\&lt;br /&gt;
:\&lt;br /&gt;
:\&lt;br /&gt;
#Settings\&lt;br /&gt;
Autokorrektur:pvCorrectionFactor_Auto \&lt;br /&gt;
Wetter:graphicShowWeather\&lt;br /&gt;
History:graphicHistoryHour\&lt;br /&gt;
ShowNight:graphicShowNight\&lt;br /&gt;
Debug:ctrlDebug\&lt;br /&gt;
FCU-Modus:FCU-Betriebsmodus@FCU&lt;br /&gt;
attr Forecast graphicHistoryHour 4&lt;br /&gt;
attr Forecast graphicHourCount 24&lt;br /&gt;
attr Forecast graphicLayoutType double&lt;br /&gt;
attr Forecast graphicShowDiff top&lt;br /&gt;
attr Forecast graphicShowNight 1&lt;br /&gt;
attr Forecast graphicShowWeather 1&lt;br /&gt;
attr Forecast group Energy Meter&lt;br /&gt;
attr Forecast room 020_PV,Energie&lt;br /&gt;
attr Forecast setupBatteryDev01 SBS25 pin=-pout:kW pout=total_pac:kW intotal=bat_loadtotal:kWh outtotal=bat_unloadtotal:kWh charge=chargestatus cap=9800 show=2&lt;br /&gt;
attr Forecast setupBatteryDev02 SBS25_2 pin=-pout:kW pout=total_pac:kW intotal=bat_loadtotal:kWh outtotal=bat_unloadtotal:kWh charge=chargestatus cap=9800 show=2&lt;br /&gt;
attr Forecast setupInverterDev01 SB25 pv=total_pac:kW etotal=etotal:kWh capacity=2500 strings=GarageSE limit=70&lt;br /&gt;
attr Forecast setupInverterDev02 SB30 pv=total_pac:kW etotal=etotal:kWh capacity=3000 strings=GarageNW,HausNW limit=70&lt;br /&gt;
attr Forecast setupInverterDev03 SB40 pv=total_pac:kW etotal=etotal:kWh capacity=4000 strings=HausSE1,HausSE2,HausSW limit=70&lt;br /&gt;
attr Forecast setupInverterStrings GarageSE,GarageNW,HausNW,HausSW,HausSE1,HausSE2&lt;br /&gt;
attr Forecast setupMeterDev SMA_Energymeter gcon=Bezug_Wirkleistung:W contotal=Bezug_Wirkleistung_Zaehler:kWh gfeedin=Einspeisung_Wirkleistung:W feedtotal=Einspeisung_Wirkleistung_Zaehler:kWh conprice=0.25:€ feedprice=0.08123:€&lt;br /&gt;
attr Forecast setupOtherProducer01 icon=Heizung_FCU_green@red MB_USRW610_004 pcurr=Power_L1__W:W etotal=Energy_L1_import__kWh:kWh&lt;br /&gt;
attr Forecast setupRadiationAPI DWD&lt;br /&gt;
attr Forecast setupStringPeak GarageSE=2.75 GarageNW=3.200 HausNW=2.230 HausSW=2.230 HausSE1=2.200 HausSE2=2.200&lt;br /&gt;
attr Forecast setupWeatherDev1 DWD&lt;br /&gt;
attr Forecast stateFormat Current_PV&lt;br /&gt;
attr Forecast userReadings Current_BatCharge999 {((ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;chargestatus&amp;quot;,0) * 10 * ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;bat_rated_capacity&amp;quot;,0))  + (ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;chargestatus&amp;quot;,0) * 10 * ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;bat_rated_capacity&amp;quot;,0))) / ( (ReadingsNum(&amp;quot;SBS25&amp;quot;,&amp;quot;bat_rated_capacity&amp;quot;,0) * 1000)  + (ReadingsNum(&amp;quot;SBS25_2&amp;quot;,&amp;quot;bat_rated_capacity&amp;quot;,0)*1000))*100}&lt;br /&gt;
attr Forecast verbose 2&lt;br /&gt;
&lt;br /&gt;
setstate Forecast 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:55 .FCU_FCU-Betriebsmodus 2&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:55 .Forecast_ctrlDebug none&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:55 .Forecast_graphicHistoryHour 4&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:55 .Forecast_graphicShowNight 1&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:55 .Forecast_graphicShowWeather 1&lt;br /&gt;
setstate Forecast 2025-01-13 08:24:25 .associatedWith SMA_Energymeter FBDECT_fbahahttp_11657_0127183 FBDECT_fbahahttp_E8_DF_70_07_3E_57 FBDECT_fbahahttp_E8_DF_70_07_42_0B FBDECT_fbahahttp_11657_0067275 FBDECT_fbahahttp_34_31_C4_D4_31_37 tuya_local_bf5037060f450bdbd4rl0q tuya_local_bfac44fb487476efd1vhdu SBS25 SBS25_2 SB25 SB30 SB40 DWD MB_USRW610_004&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 .lastupdateForecastValues 1736790834&lt;br /&gt;
setstate Forecast 2025-01-13 01:00:05 .pvCorrectionFactor_01_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 01:00:05 .pvCorrectionFactor_01_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 02:00:04 .pvCorrectionFactor_02_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 02:00:04 .pvCorrectionFactor_02_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 03:00:04 .pvCorrectionFactor_03_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 03:00:04 .pvCorrectionFactor_03_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 04:00:05 .pvCorrectionFactor_04_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 04:00:05 .pvCorrectionFactor_04_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 05:00:05 .pvCorrectionFactor_05_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 05:00:05 .pvCorrectionFactor_05_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 06:00:06 .pvCorrectionFactor_06_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 06:00:06 .pvCorrectionFactor_06_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 07:00:04 .pvCorrectionFactor_07_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 07:00:04 .pvCorrectionFactor_07_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 08:00:03 .pvCorrectionFactor_08_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 08:00:03 .pvCorrectionFactor_08_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 09:00:04 .pvCorrectionFactor_09_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 09:00:04 .pvCorrectionFactor_09_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 10:00:05 .pvCorrectionFactor_10_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 10:00:05 .pvCorrectionFactor_10_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 11:00:05 .pvCorrectionFactor_11_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 11:00:05 .pvCorrectionFactor_11_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 12:00:02 .pvCorrectionFactor_12_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 12:00:02 .pvCorrectionFactor_12_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 13:00:02 .pvCorrectionFactor_13_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 13:00:02 .pvCorrectionFactor_13_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 14:00:03 .pvCorrectionFactor_14_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 14:00:03 .pvCorrectionFactor_14_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 15:00:05 .pvCorrectionFactor_15_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 15:00:05 .pvCorrectionFactor_15_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 16:00:06 .pvCorrectionFactor_16_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 16:00:06 .pvCorrectionFactor_16_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 17:00:05 .pvCorrectionFactor_17_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 17:00:05 .pvCorrectionFactor_17_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 18:00:04 .pvCorrectionFactor_18_apipercentil done&lt;br /&gt;
setstate Forecast 2025-01-13 18:00:04 .pvCorrectionFactor_18_cloudcover done&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 .pvCorrectionFactor_Auto_Soll on_complex_ai&lt;br /&gt;
setstate Forecast 2025-01-13 01:00:05 .signaldone_01 done&lt;br /&gt;
setstate Forecast 2025-01-13 02:00:04 .signaldone_02 done&lt;br /&gt;
setstate Forecast 2025-01-13 03:00:04 .signaldone_03 done&lt;br /&gt;
setstate Forecast 2025-01-13 04:00:05 .signaldone_04 done&lt;br /&gt;
setstate Forecast 2025-01-13 05:00:05 .signaldone_05 done&lt;br /&gt;
setstate Forecast 2025-01-13 06:00:06 .signaldone_06 done&lt;br /&gt;
setstate Forecast 2025-01-13 07:00:04 .signaldone_07 done&lt;br /&gt;
setstate Forecast 2025-01-13 08:00:03 .signaldone_08 done&lt;br /&gt;
setstate Forecast 2025-01-13 09:00:04 .signaldone_09 done&lt;br /&gt;
setstate Forecast 2025-01-13 10:00:05 .signaldone_10 done&lt;br /&gt;
setstate Forecast 2025-01-13 11:00:05 .signaldone_11 done&lt;br /&gt;
setstate Forecast 2025-01-13 12:00:02 .signaldone_12 done&lt;br /&gt;
setstate Forecast 2025-01-13 13:00:02 .signaldone_13 done&lt;br /&gt;
setstate Forecast 2025-01-13 14:00:03 .signaldone_14 done&lt;br /&gt;
setstate Forecast 2025-01-13 15:00:05 .signaldone_15 done&lt;br /&gt;
setstate Forecast 2025-01-13 16:00:06 .signaldone_16 done&lt;br /&gt;
setstate Forecast 2025-01-13 17:00:05 .signaldone_17 done&lt;br /&gt;
setstate Forecast 2025-01-13 18:00:04 .signaldone_18 done&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_ChargeUnrestricted_01 1&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_ChargeUnrestricted_02 1&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_ChargeRequest_01 1&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_ChargeRequest_02 1&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour00_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour00_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour01_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour01_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour02_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour02_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour03_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour03_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour04_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour04_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour05_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour05_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour06_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour06_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour07_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour07_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour08_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour08_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour09_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour09_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour10_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour10_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour11_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour11_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour12_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour12_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour13_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour13_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour14_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour14_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour15_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour15_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour16_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour16_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour17_SoCforecast_01 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour17_SoCforecast_02 10.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour18_SoCforecast_01 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour18_SoCforecast_02 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour19_SoCforecast_01 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour19_SoCforecast_02 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour20_SoCforecast_01 42.6 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour20_SoCforecast_02 42.6 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour21_SoCforecast_01 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour21_SoCforecast_02 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour22_SoCforecast_01 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour22_SoCforecast_02 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour23_SoCforecast_01 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_NextHour23_SoCforecast_02 40.0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_OptimumTargetSoC_01 40 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Battery_OptimumTargetSoC_02 40 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_AutarkyRate 83 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:55 Current_BatCharge999 10&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_BatCharge_01 12 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_BatCharge_02 8 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_Consumption 626 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_GridConsumption 2 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_GridFeedIn 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_PP_01 746.0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_PV 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_PowerBatIn_01 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_PowerBatIn_02 132 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_PowerBatOut_01 10 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_PowerBatOut_02 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_SelfConsumption 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_SelfConsumptionRate 0 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Current_Surplus 120 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:00:00 LastHourGridconsumptionReal 5 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:00:00 LastHourPVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:00:00 LastHourPVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 NextHours_Sum01_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 NextHours_Sum02_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 NextHours_Sum03_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 NextHours_Sum04_ConsumptionForecast 2944 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 NextHours_Sum04_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 RestOfDayConsumptionForecast 3609 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 RestOfDayPVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 Today_Hour01_BatIn_01 272 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 Today_Hour01_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 Today_Hour01_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 Today_Hour01_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 Today_Hour01_GridConsumption 1 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 Today_Hour01_GridFeedIn 1 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 Today_Hour01_PPreal_01 748 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 Today_Hour01_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 Today_Hour02_BatIn_01 266 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 Today_Hour02_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 Today_Hour02_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 Today_Hour02_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 Today_Hour02_GridConsumption 1 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 Today_Hour02_GridFeedIn 1 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 Today_Hour02_PPreal_01 787 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 Today_Hour02_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 Today_Hour03_BatIn_01 271 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 Today_Hour03_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 Today_Hour03_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 Today_Hour03_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 Today_Hour03_GridConsumption 2 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 Today_Hour03_GridFeedIn 2 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 Today_Hour03_PPreal_01 750 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 Today_Hour03_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 Today_Hour04_BatIn_01 266 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 Today_Hour04_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 Today_Hour04_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 Today_Hour04_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 Today_Hour04_GridConsumption 1 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 Today_Hour04_GridFeedIn 1 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 Today_Hour04_PPreal_01 745 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 Today_Hour04_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 Today_Hour05_BatIn_01 267 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 Today_Hour05_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 Today_Hour05_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 Today_Hour05_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 Today_Hour05_GridConsumption 2 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 Today_Hour05_GridFeedIn 2 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 Today_Hour05_PPreal_01 758 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 Today_Hour05_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 Today_Hour06_BatIn_01 255 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 Today_Hour06_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 Today_Hour06_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 Today_Hour06_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 Today_Hour06_GridConsumption 1 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 Today_Hour06_GridFeedIn 1 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 Today_Hour06_PPreal_01 752 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 Today_Hour06_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 Today_Hour07_BatIn_01 226 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 Today_Hour07_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 Today_Hour07_BatOut_01 50 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 Today_Hour07_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 Today_Hour07_GridConsumption 2 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 Today_Hour07_GridFeedIn 2 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 Today_Hour07_PPreal_01 681 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 Today_Hour07_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 Today_Hour08_BatIn_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 Today_Hour08_BatIn_02 233 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 Today_Hour08_BatOut_01 845 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 Today_Hour08_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 Today_Hour08_GridConsumption 4 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 Today_Hour08_GridFeedIn 4 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 Today_Hour08_PPreal_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 Today_Hour08_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_BatIn_01 37 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_BatIn_02 90 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_BatOut_01 351 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_BatOut_02 188 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_GridConsumption 447 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_GridFeedIn 4 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_PPreal_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_PVforecast 127 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 Today_Hour09_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_BatIn_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_GridConsumption 1650 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_GridFeedIn 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_PPreal_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_PVforecast 478 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 Today_Hour10_PVreal 26 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_BatIn_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_GridConsumption 513 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_GridFeedIn 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_PPreal_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_PVforecast 868 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 Today_Hour11_PVreal 97 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_BatIn_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_BatIn_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_GridConsumption 576 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_GridFeedIn 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_PPreal_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_PVforecast 1157 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 Today_Hour12_PVreal 320 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_BatIn_01 8 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_BatIn_02 4 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_GridConsumption 1272 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_GridFeedIn 7 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_PPreal_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_PVforecast 1238 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 Today_Hour13_PVreal 945 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_BatIn_01 410 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_BatIn_02 53 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_BatOut_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_BatOut_02 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_GridConsumption 955 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_GridFeedIn 31 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_PPreal_01 562 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_PVforecast 1168 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 Today_Hour14_PVreal 1410 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_BatIn_01 703 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_BatIn_02 500 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_BatOut_01 22 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_BatOut_02 18 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_GridConsumption 32 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_GridFeedIn 71 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_PPreal_01 777 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_PVforecast 1630 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 Today_Hour15_PVreal 1416 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_BatIn_01 296 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_BatIn_02 70 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_BatOut_01 74 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_BatOut_02 258 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_GridConsumption 13 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_GridFeedIn 17 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_PPreal_01 732 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_PVforecast 880 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 Today_Hour16_PVreal 1051 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_BatIn_01 47 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_BatIn_02 126 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_BatOut_01 102 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_BatOut_02 75 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_GridConsumption 15 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_GridFeedIn 23 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_PPreal_01 771 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_PVforecast 117 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 Today_Hour17_PVreal 86 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 Today_Hour18_BatIn_01 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 Today_Hour18_BatIn_02 410 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 Today_Hour18_BatOut_01 758 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 Today_Hour18_BatOut_02 67 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 Today_Hour18_GridConsumption 5 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 Today_Hour18_GridFeedIn 5 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 Today_Hour18_PPreal_01 723 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 Today_Hour18_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_Hour19_BatIn_01 349 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_Hour19_BatIn_02 124 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_Hour19_BatOut_01 73 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_Hour19_BatOut_02 450 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_Hour19_GridConsumption 8 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_Hour19_GridFeedIn 6 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_Hour19_PPreal_01 671 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_Hour19_PVreal 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_MaxPVforecast 1630 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_MaxPVforecastTime 2025-01-13 14:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_PVdeviation 30.17 %&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_PVforecast 7663 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_PVreal 5351 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_SunRise 08:28&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Today_SunSet 16:46&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_ConsumptionForecast 17043 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour01_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour02_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour03_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour04_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour05_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour06_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour07_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour08_PVforecast 10 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour09_PVforecast 161 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour10_PVforecast 275 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour11_PVforecast 532 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour12_PVforecast 730 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour13_PVforecast 1252 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour14_PVforecast 818 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour15_PVforecast 1465 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour16_PVforecast 303 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour17_PVforecast 20 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour18_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour19_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour20_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour21_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour22_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour23_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_Hour24_PVforecast 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_PVforecast 5566 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_SunRise 08:27&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 Tomorrow_SunSet 16:47&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer01 name=&#039;_Waschmaschine&#039; state=&#039;off&#039; mode=&#039;can&#039; planningstate=&#039;planned&#039;&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer01_currentPower 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer01_planned_start 14.01.2025 09:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer01_planned_stop 14.01.2025 11:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer02 name=&#039;_Esszimmer&#039; state=&#039;on&#039; mode=&#039;can&#039; planningstate=&#039;planned&#039;&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer02_currentPower 15.3 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer02_planned_start 14.01.2025 08:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer02_planned_stop 14.01.2025 09:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer03 name=&#039;_FCU&#039; state=&#039;on&#039; mode=&#039;can&#039; planningstate=&#039;planned&#039;&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer03_currentPower 7.15 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer03_planned_start 14.01.2025 07:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer03_planned_stop 14.01.2025 08:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer04 name=&#039;_Brunnen&#039; state=&#039;off&#039; mode=&#039;can&#039; planningstate=&#039;planned&#039;&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer04_currentPower 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer04_planned_start 14.01.2025 08:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer04_planned_stop 14.01.2025 09:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer05 name=&#039;_Zisterne&#039; state=&#039;off&#039; mode=&#039;can&#039; planningstate=&#039;planned&#039;&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer05_currentPower 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer05_planned_start 14.01.2025 07:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer05_planned_stop 14.01.2025 08:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer06 name=&#039;SW Trockner&#039; state=&#039;unknown&#039; mode=&#039;can&#039; planningstate=&#039;planned&#039;&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer06_currentPower 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer06_planned_start 14.01.2025 07:00:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer06_planned_stop 14.01.2025 08:30:00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer07 name=&#039;SW Urlaubslicht-Wohnzimmer&#039; state=&#039;on&#039; mode=&#039;can&#039; planningstate=&#039;noSchedule&#039; info=&#039;von extern umgeschaltet&#039;&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 consumer07_currentPower 0 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 nextCycletime 18:54:09&lt;br /&gt;
setstate Forecast 2025-01-13 10:00:05 pvCorrectionFactor_10 0.53 (automatic - old factor: 1.00, Sun Alt range: 5, Cloud range: 75, Days in range: 1)&lt;br /&gt;
setstate Forecast 2025-01-13 11:00:05 pvCorrectionFactor_11 0.56 (automatic - old factor: 1.00, Sun Alt range: 10, Cloud range: 70, Days in range: 1)&lt;br /&gt;
setstate Forecast 2025-01-13 12:00:02 pvCorrectionFactor_12 0.64 (automatic - old factor: 1.00, Sun Alt range: 15, Cloud range: 60, Days in range: 1)&lt;br /&gt;
setstate Forecast 2025-01-13 13:00:02 pvCorrectionFactor_13 0.88 (automatic - old factor: 1.00, Sun Alt range: 15, Cloud range: 60, Days in range: 1)&lt;br /&gt;
setstate Forecast 2025-01-13 14:00:03 pvCorrectionFactor_14 1.10 (automatic - old factor: 1.00, Sun Alt range: 15, Cloud range: 50, Days in range: 1)&lt;br /&gt;
setstate Forecast 2025-01-13 15:00:05 pvCorrectionFactor_15 1.01 (automatic - old factor: 1.06, Sun Alt range: 15, Cloud range: 45, Days in range: 2)&lt;br /&gt;
setstate Forecast 2025-01-13 16:00:06 pvCorrectionFactor_16 1.09 (automatic - old factor: 1.00, Sun Alt range: 10, Cloud range: 45, Days in range: 1)&lt;br /&gt;
setstate Forecast 2025-01-13 17:00:05 pvCorrectionFactor_17 0.28 (automatic - old factor: 0.52, Sun Alt range: 0, Cloud range: 45, Days in range: 2)&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 pvCorrectionFactor_Auto on_complex_ai&lt;br /&gt;
setstate Forecast 2024-10-30 19:42:19 setupStringAzimuth GarageSE=-55 GarageNW=125 HausNW=125 HausSW=35 HausSE1=-55 HausSE2=-55&lt;br /&gt;
setstate Forecast 2024-10-30 19:37:38 setupStringDeclination GarageSE=40 GarageNW=40 HausNW=50 HausSW=50 HausSE1=50 HausSE2=50&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_BatPowerIn_Sum 132 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_BatPowerOut_Sum 10 W&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_SunHours_Remain 0.00&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_SunMinutes_Remain 0&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_allStringsFullfilled 1&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_conForecastTillNextSunrise 9467 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_currentAPIinterval 0&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_currentRunMtsConsumer_01 132 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_currentRunMtsConsumer_02 184 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_currentRunMtsConsumer_03 329512 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_currentRunMtsConsumer_04 200 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_currentRunMtsConsumer_05 27 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_currentRunMtsConsumer_06 193 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_currentRunMtsConsumer_07 106 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_dayAfterTomorrowPVforecast 7344 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_daysUntilBatteryCare_01 12&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_daysUntilBatteryCare_02 12&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_lastretrieval_time 2025-01-13 18:53:54&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_lastretrieval_timestamp 1736790834&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_response_message success&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeAvgDayConsumer_01 545.94 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeAvgDayConsumer_02 382.10 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeAvgDayConsumer_03 1430.13 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeAvgDayConsumer_04 262.05 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeAvgDayConsumer_05 28.80 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeAvgDayConsumer_06 622.63 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeAvgDayConsumer_07 276.51 min&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeCentralTask 0.3744&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeLastAPIAnswer -&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeLastAPIProc -&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_runTimeTrainAI 1.2529&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayBatIn_01 3683.0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayBatIn_02 1617.0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayBatOut_01 2287.0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayBatOut_02 1057.0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayConForecastTillSunset 0 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 00:59:59 special_todayConsumptionForecast_01 509 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 01:59:58 special_todayConsumptionForecast_02 499 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 02:59:53 special_todayConsumptionForecast_03 501 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 03:59:52 special_todayConsumptionForecast_04 511 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 04:59:56 special_todayConsumptionForecast_05 503 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 05:59:59 special_todayConsumptionForecast_06 495 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 06:59:52 special_todayConsumptionForecast_07 504 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 07:59:50 special_todayConsumptionForecast_08 561 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 08:59:57 special_todayConsumptionForecast_09 768 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 09:59:58 special_todayConsumptionForecast_10 783 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 10:59:58 special_todayConsumptionForecast_11 692 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 11:59:49 special_todayConsumptionForecast_12 791 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 12:59:49 special_todayConsumptionForecast_13 910 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 13:59:49 special_todayConsumptionForecast_14 1022 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 14:59:49 special_todayConsumptionForecast_15 965 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 15:59:50 special_todayConsumptionForecast_16 812 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 16:59:49 special_todayConsumptionForecast_17 884 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 17:59:54 special_todayConsumptionForecast_18 928 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayConsumptionForecast_19 874 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayConsumptionForecast_20 763 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayConsumptionForecast_21 750 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayConsumptionForecast_22 765 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayConsumptionForecast_23 643 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayConsumptionForecast_24 601 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayDoneAPIcalls 0&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayDoneAPIrequests 4532&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayGridConsumption 5500.9 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayGridFeedIn 178.9 Wh&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayMaxAPIcalls n.a.&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayRemainingAPIcalls n.a.&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:54 special_todayRemainingAPIrequests n.a.&lt;br /&gt;
setstate Forecast 2025-01-13 18:53:55 state updated&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
So sollte es dann als Ergebnis aussehen:&lt;br /&gt;
[[Datei:Bildschirmfoto 2025-01-13.png|zentriert|mini|Ergebnis nach kompletter Einrichtung]]&lt;br /&gt;
[[Datei:Bildschirmfoto 2025-01-13 Teil II.png|alternativtext=Unterer Teil der Anzeige|zentriert|mini]]&lt;br /&gt;
&lt;br /&gt;
== Praxisbeispiele und Lösungsansätze für Steuerungen ==&lt;br /&gt;
=== Fallstudie: Trockner darf pausiert werden, wenn nicht genug PV-Überschuss vorhanden ist, soll aber nach spätestens X Stunden fertig sein ===&lt;br /&gt;
Für diese Aufgabenstellung sind mehrere Schlüssel essentiell wichtig, &#039;&#039;&#039;power&#039;&#039;&#039;, &#039;&#039;&#039;mintime&#039;&#039;&#039;, &#039;&#039;&#039;mode&#039;&#039;&#039; und &#039;&#039;&#039;interruptable&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Die Bedingung, dass der Trockner nach spätestens X Stunden fertig sein soll, steht in einem Widerspruch zu der Möglichkeit den Trockner bei zu wenig PV-Überschuss unterbrechen zu können. Im Extremfall könnte nach dem Start die gesamte Planungszeit ungenügender Überschuss vorliegen und der Trockner nicht arbeiten. Der Schlüssel &#039;&#039;&#039;mintime&#039;&#039;&#039; (in Minuten) wird nun wie folgt angesetzt:&lt;br /&gt;
&lt;br /&gt;
 mintime = 2,5 x &amp;lt;gewöhnliche Betriebszeit für einen Trockengang (mneed, z.B. 120)&amp;gt; = 300 Minuten&lt;br /&gt;
&lt;br /&gt;
Das bedeutet, der Trockner wird nach 300 Minuten Laufzeit abgeschaltet werden bzw. vom Netz getrennt. Der Trockenvorgang wird natürlich bereits nach 120 Minuten beendet sein, sofern nach Start keine Unterbrechnung des Vorganges erfolgte. Wurde der Vorgang unterbrochen, soll der Trockner innerhalb &lt;br /&gt;
&lt;br /&gt;
 X+120 bis X+300 &lt;br /&gt;
&lt;br /&gt;
fertig sein. &lt;br /&gt;
&lt;br /&gt;
Demnach ist die ausgeführte Laufzeit des Trockners permanent zu überwachen, zu summieren (rtsum) und die notwendige Restzeit (mneed - rtsum) mit der noch verbleibenden Restzeit (mrest) bis zur geplanten Abschaltung des Consumers zu vergleichen. Ist der Consumer gestartet, wird die Laufzeit in der pvHistory für jede Stunde des Tages im Schlüssel &#039;&#039;minutescsmXX&#039;&#039; (XX = Consumernummer) aufgezeichnet und kann darüber ausgewertet werden. Somit ist:&lt;br /&gt;
&lt;br /&gt;
 msum = for (01 .. 24) {Summe von minutescsmXX} des aktuellen Tages&lt;br /&gt;
&lt;br /&gt;
Solange die Bedingung &lt;br /&gt;
&lt;br /&gt;
 mrest &amp;gt;= (mneed - msum)&lt;br /&gt;
&lt;br /&gt;
zutrifft, darf der Trockner unterbrochen werden, anderenfalls darf er nicht mehr unterbrochen werden da die Restzeit evtl. nicht ausreichen könnte um den Vorgang abzuschließen. Für die Planung des Trockners wird der Consumer wie gewöhnlich nach dem Bedarf im Modul registriert. Für die Steuerung der Unterbrechbarkeit wird noch ein Code erstellt, welcher im Trockner-Device &#039;&#039;Dryerdev&#039;&#039; das Reading &#039;&#039;SF_Int&#039;&#039; zur Unterbrechnungssteuerung verwaltet. Dieses Reading wird dem Schlüssel &#039;&#039;&#039;interruptable&#039;&#039;&#039; übergeben. Für das Beispiel wird der Consumer &#039;07&#039; verwendet, es kann natürlich jede andere freie Nummer verwendet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; consumer07 Dryerdev:Trockner&lt;br /&gt;
                        icon=scene_cloves_dryer type=dryer power=2000 mode=must mintime=300 &lt;br /&gt;
                        on=on off=off etotal=energy_Wh:Wh pcurr=power:W&lt;br /&gt;
                        auto=automatic asynchron=1&lt;br /&gt;
                        interruptable=Dryerdev:SF_Int:1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Kombination &#039;&#039;&#039;auto=automatic&#039;&#039;&#039; eröffnet die Möglickeit, in der Consumer-Legende den Trockner-Start zusätzlich manuell freizugeben oder zu verbieten. &lt;br /&gt;
&lt;br /&gt;
Im nachfolgenden Code werden modulinterne Subroutinen verwendet. Diese sind inklusive dem Paket &#039;&#039;FHEM::SolarForecast::&#039;&#039; anzugeben. Die erstellte Subroutine wird in die 99_mySolarForecastUtils.pm eingefügt. Die Datei 99_mySolarForecastUtils.pm wird vorher von 99_myUtils.pm kopiert und enthält für die Übersichtlichkeit nur Routinen für SolarForecast.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
############################################################################&lt;br /&gt;
#   Trocknersteuerung (einfügen in 99_mySolarForecastUtils.pm) &lt;br /&gt;
############################################################################&lt;br /&gt;
sub dryControl {&lt;br /&gt;
  my $name  = shift;&lt;br /&gt;
  my $c     = shift;                                                              # Nummer des Verbrauchers, z.B. 07&lt;br /&gt;
  my $mneed = shift;                                                              # gewöhlich benötigte Zeit für &lt;br /&gt;
                                                                                  # einen Trockengang, z.B. 120 (Minuten)&lt;br /&gt;
  &lt;br /&gt;
  $c            = sprintf &amp;quot;%02d&amp;quot;, $c;                                             # falls führende 0 vergessen wird&lt;br /&gt;
  my $dryer     = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;name&#039;, &#039;&#039;);       # Devicename des Trockners&lt;br /&gt;
  my $plstate   = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;planstate&#039;, &#039;&#039;); &lt;br /&gt;
  my $simpCstat = FHEM::SolarForecast::simplifyCstate ($plstate);                 # akt. Status des Consumers&lt;br /&gt;
&lt;br /&gt;
  if ($simpCstat =~ /started|interrupt|continu/xs) {                              # Vorgang ist gestartet&lt;br /&gt;
      my $t       = time;&lt;br /&gt;
      my $startts = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;planswitchon&#039;,  &#039;&#039;);&lt;br /&gt;
      my $stopts  = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;planswitchoff&#039;, &#039;&#039;);&lt;br /&gt;
      return if(!$startts || !$stopts);&lt;br /&gt;
      &lt;br /&gt;
      my $mrest = sprintf &#039;%.0f&#039;, (($stopts - $t) / 60);                         # Restlaufzeit (Minuten)      &lt;br /&gt;
      my $dt     = FHEM::SolarForecast::timestringsFromOffset ($name, $startts, 0);&lt;br /&gt;
      my $day    = $dt-&amp;gt;{day};&lt;br /&gt;
      my $hstart = int $dt-&amp;gt;{hour} + 1;                                          # lfd. Stunde bei Trockner-Start &lt;br /&gt;
      my $msum   = 0;&lt;br /&gt;
	  &lt;br /&gt;
      for my $hod (1..24) {                                                      # bisherige Laufzeit des Trockners&lt;br /&gt;
          next if($hod &amp;lt; $hstart);&lt;br /&gt;
          $hod = sprintf &amp;quot;%02d&amp;quot;, $hod;&lt;br /&gt;
          $msum += FHEM::SolarForecast::HistoryVal ($name, $day, $hod, &amp;quot;minutescsm${c}&amp;quot;, 0);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      my $dhash = $defs{$dryer};&lt;br /&gt;
&lt;br /&gt;
      if ($mrest &amp;gt;= ($mneed - $msum)) {&lt;br /&gt;
          readingsSingleUpdate ($dhash, &#039;SF_Int&#039;, 1, 0);                        # Interrupt-Freigabe&lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
          readingsSingleUpdate ($dhash, &#039;SF_Int&#039;, 0, 0);                        # keine Interrupt-Freigabe&lt;br /&gt;
  &lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
return;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Damit die Routine mit jedem Zyklus im Modul ausgeführt wird, legen wir sie im Attribut &#039;&#039;&#039;ctrlUserExitFn&#039;&#039;&#039; an. Es werden der Name des SolarForecast-Devices, die Verbrauchernummer (07) und die gewöhnliche Laufzeit des Trockners für einen Trockenvorgang (120 Minuten) übergeben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr &amp;lt;Name&amp;gt; ctrlUserExitFn  {  &lt;br /&gt;
                               ::dryControl ($name, &#039;07&#039;, 120);&lt;br /&gt;
                            }&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Fallstudie: Umwälzpumpe Pool soll X Stunden am Tag laufen. Ist kein PV-Überschuß vorhanden, müssen die X Stunden/Tag trotzdem erreicht werden ===&lt;br /&gt;
&lt;br /&gt;
Die Vorgehensweise ähnelt der Fallstudie zuvor. Verändernd kommt hinzu, dass der Planungszeitraum bewusst sehr lang angesetzt wird mit der Option, den Zyklus des Consumers vorfristig zu beenden sobald die Laufzeit von X Stunden am Tag erreicht ist. &lt;br /&gt;
Im folgenden Beispiel soll die Pumpe 5 Stunden am Tag (300 Minuten) laufen und dabei mögliche PV-Überschüsse ausnutzen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 attr &amp;lt;Name&amp;gt; consumer07 Pump:Zirkulationspumpe&lt;br /&gt;
                        icon=sani_pump type=other power=50 mode=must mintime=780 notafter=09&lt;br /&gt;
                        on=on off=off etotal=energy_Wh:Wh pcurr=power:W&lt;br /&gt;
                        auto=automatic &lt;br /&gt;
                        interruptable=1 swoffcond=Pump:SF_Abort:1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit dieser Registrierung wird die Pumpe ca. 09 Uhr täglich starten. Wenn kein bzw. ungenügender PV-Überschuß vorhanden ist, erfolgt eine Unterbrechung nach dem Start. Ist genügender PV-Überschuß (wieder) vorhanden, erfolgt keine Unterbrechnung (mehr). Zusätzlich wird über den Schlüssel &#039;&#039;&#039;swoffcond&#039;&#039;&#039; eine vorfristige Beendigung veranlasst, sobald die gewünschte Tageslaufzeit erreicht ist.&lt;br /&gt;
&lt;br /&gt;
Zur Verwaltung des Schlüssels &#039;&#039;interruptable&#039;&#039; und des Readings &#039;&#039;SF_Abort&#039;&#039; verwenden wir eine leicht veränderte Subroutine aus dem vorhergehenden Fallbeispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
############################################################################&lt;br /&gt;
#   Pumpensteuerung (einfügen in 99_mySolarForecastUtils.pm) &lt;br /&gt;
############################################################################&lt;br /&gt;
sub pumpControl {&lt;br /&gt;
  my $name  = shift;&lt;br /&gt;
  my $c     = shift;                                                              # Nummer des Verbrauchers, z.B. 07&lt;br /&gt;
  my $mneed = shift;                                                              # Soll-Pumpenzeit, z.B. 300 (Minuten)&lt;br /&gt;
  &lt;br /&gt;
  $c            = sprintf &amp;quot;%02d&amp;quot;, $c;                                             # falls führende 0 vergessen wird&lt;br /&gt;
  my $pump      = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;name&#039;, &#039;&#039;);       # Devicename der Pumpe&lt;br /&gt;
  my $plstate   = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;planstate&#039;, &#039;&#039;);&lt;br /&gt;
  my $intbl     = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;interruptable&#039;, 1); &lt;br /&gt;
  my $simpCstat = FHEM::SolarForecast::simplifyCstate ($plstate);                 # akt. Status des Consumers&lt;br /&gt;
  my $dhash     = $defs{$pump};&lt;br /&gt;
&lt;br /&gt;
  readingsSingleUpdate ($dhash, &#039;SF_Abort&#039;, 0, 0);                                # default keine Zyklusbeendigung&lt;br /&gt;
&lt;br /&gt;
  if ($simpCstat =~ /started|interrupt|continu/xs) {                              # Vorgang ist gestartet&lt;br /&gt;
      my $t       = time;&lt;br /&gt;
      my $startts = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;planswitchon&#039;,  &#039;&#039;);&lt;br /&gt;
      my $stopts  = FHEM::SolarForecast::ConsumerVal ($name, $c, &#039;planswitchoff&#039;, &#039;&#039;);&lt;br /&gt;
      return if(!$startts || !$stopts);&lt;br /&gt;
      &lt;br /&gt;
      my $mrest = sprintf &#039;%.0f&#039;, (($stopts - $t) / 60);                         # Restlaufzeit (Minuten)      &lt;br /&gt;
      my $dt     = FHEM::SolarForecast::timestringsFromOffset ($name, $startts, 0);&lt;br /&gt;
      my $day    = $dt-&amp;gt;{day};&lt;br /&gt;
      my $hstart = int $dt-&amp;gt;{hour} + 1;                                          # lfd. Stunde bei Pumpen Start &lt;br /&gt;
      my $msum   = 0;&lt;br /&gt;
	  &lt;br /&gt;
      for my $hod (1..24) {                                                      # bisherige Laufzeit der Pumpe&lt;br /&gt;
          next if($hod &amp;lt; $hstart);&lt;br /&gt;
          $hod = sprintf &amp;quot;%02d&amp;quot;, $hod;&lt;br /&gt;
          $msum += FHEM::SolarForecast::HistoryVal ($name, $day, $hod, &amp;quot;minutescsm${c}&amp;quot;, 0);&lt;br /&gt;
      }&lt;br /&gt;
     &lt;br /&gt;
      if ($msum &amp;gt;= $mneed) {&lt;br /&gt;
          readingsSingleUpdate ($dhash, &#039;SF_Abort&#039;, 1, 0);                       # vorfristige Zyklusbeendigung&lt;br /&gt;
          return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ($mrest &amp;gt;= ($mneed - $msum)) {                        &lt;br /&gt;
          fhem (&amp;quot;set $name attrKeyVal consumer$c interruptable=1&amp;quot;) if(!$intbl);  # Interrupt-Freigabe&lt;br /&gt;
      }&lt;br /&gt;
      else {                        &lt;br /&gt;
          fhem (&amp;quot;set $name attrKeyVal consumer$c interruptable=0&amp;quot;) if($intbl);   # keine Interrupt-Freigabe&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
return;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Befehl &#039;&#039;attrKeyVal&#039;&#039; setzt den Schlüssel &#039;&#039;interruptable&#039;&#039; im Attribut &#039;&#039;consumer07&#039;&#039; dynamisch. Diese Strukturänderung wird automatisch im System gespeichert, sofern &#039;&#039;global-&amp;gt;autosave=1&#039;&#039; gesetzt ist. Diese Einstellung ist der FHEM default.  &lt;br /&gt;
&lt;br /&gt;
Damit die Routine mit jedem Zyklus im Modul ausgeführt wird, legen wir sie im Attribut &#039;&#039;&#039;ctrlUserExitFn&#039;&#039;&#039; an. Es werden der Name des SolarForecast-Devices, die Verbrauchernummer (07) und die Mindestlaufzeit der Umwälzpumpe (300 Minuten) übergeben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr &amp;lt;Name&amp;gt; ctrlUserExitFn  {  &lt;br /&gt;
                               ::pumpControl ($name, &#039;07&#039;, 300);&lt;br /&gt;
                            }&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dynamische Ladestromsteuerung eines Victron MultiPlus II Chargers mit Pylontech Batterie ===&lt;br /&gt;
Die nachfolgend beschriebene Lösung soll als Anregung für eigene Optimierungen verstanden werden und ist weiter ausbaufähig bzw. erweiterbar um zum Beipiel jahreszeitliche Anpassungen des Verfahrens.&lt;br /&gt;
&lt;br /&gt;
Die MultiPlus II Batteriewechselrichter von Victron sollten die Batterien nicht mit dem maximal möglichen Ladestrom beladen, da sich die Effizienz deutlich verschlechtert wenn sich die Ströme den jeweiligen Grenzwerten nähern ([https://www.victronenergy.com/upload/documents/Output-rating-operating-temperature-and-efficiency.pdf Lesestoff]). &lt;br /&gt;
Andererseits sollen die Ladeleistungen so gewählt werden, dass die verfügbare Solarenergie eine volle Aufladung der Akkus ermöglicht.&lt;br /&gt;
&lt;br /&gt;
Das Victron System ermöglicht das Auslesen und die Steuerung der Anlage via MQTT. Die Einbindung in FHEM über MQTT soll hier nicht beschrieben werden.&lt;br /&gt;
Aber wenn dies erfolgt ist, kann der Ladestrom z.B. mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
 set &amp;lt;Device&amp;gt; MaxChargeCurrent &amp;lt;Wert&amp;gt;&lt;br /&gt;
&lt;br /&gt;
eingestellt bzw. variiert werden.&lt;br /&gt;
&lt;br /&gt;
Das Modul bietet dem Nutzer die Möglichkeit in dem Attribut &#039;&#039;ctrlUserExitFn&#039;&#039; eigenen Code zur Auführung zu bringen. Der in diesem Attribut enthaltene Code wird am Ende jedes Zyklus (siehe Attribut &#039;&#039;plantControl-&amp;gt;cycleInterval&#039;&#039;) ausgeführt.&lt;br /&gt;
In dem Attribut wird dieser Code eingetragen dessen Funktion und Zusammenspiel nachfolgend erläutert wird:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{ &lt;br /&gt;
  ## Vars&lt;br /&gt;
  ########&lt;br /&gt;
  my $batdev  = (split &amp;quot; &amp;quot;, ReadingsVal ($name, &#039;currentBatteryDev&#039;, &#039;&#039;))[0];  # Batteriedevice&lt;br /&gt;
  my $vebus   = &#039;MQTT2_cerboGX_c0619ab34e08_vebus&#039;;                            # Victron Vebus Device &lt;br /&gt;
  my $mppt1   = &#039;MQTT2_cerboGX_c0619ab34e08_solarcharger_Common&#039;;              # SmartLoader Device&lt;br /&gt;
  my $maxcspc = 105;                        # max. Ladesollstrom (A) nominal&lt;br /&gt;
  my $spcorr  = 0.9;                        # Korrekturfaktor Überschuss 90%&lt;br /&gt;
  my $sch     = 0.25;                       # Verkürzungsfaktor Zeit bis Vollladung vor Sunset             &lt;br /&gt;
  &lt;br /&gt;
  my $cclvl0  = 15;                         # Ladestrom Level 0 max. 5  A (240 W) pro WR  (720  W)&lt;br /&gt;
  my $cclvl1  = 27;                         # Ladestrom Level 1 max. 9  A (432 W) pro WR  (1296 W)&lt;br /&gt;
  my $cclvl2  = 54;                         # Ladestrom Level 2 max. 18 A (864 W) pro WR  (2592 W)&lt;br /&gt;
  my $cclvl3  = 81;                         # Ladestrom Level 3 max. 27 A (1296 W) pro WR (3888 W)&lt;br /&gt;
  ###############&lt;br /&gt;
  &lt;br /&gt;
  my $cofc   = ReadingsNum ($name,  &#039;special_todayConForecastTillSunset&#039;, 0);&lt;br /&gt;
  my $pvfc   = ReadingsNum ($name,  &#039;RestOfDayPVforecast&#039;, 0);&lt;br /&gt;
  my $cpv    = ReadingsNum ($name,  &#039;Current_PV&#039;,          0);&lt;br /&gt;
  my $mppt1c = ReadingsNum ($mppt1, &#039;DC_0_Current_value&#039;,  0);             # Load I MPPT1 (max. 44 A)&lt;br /&gt;
  my $ssts   = CurrentVal  ($hash,  &#039;sunsetTodayTs&#039;,        0);&lt;br /&gt;
  my $srts   = CurrentVal  ($hash,  &#039;sunriseTodayTs&#039;,       0);&lt;br /&gt;
  my $sdiff  = ($ssts - $srts) / 3600;                                     # Sonnengang heute in h &lt;br /&gt;
  &lt;br /&gt;
  my $solh   = ReadingsNum ($name, &#039;special_SunHours_Remain&#039;, 0);          # h bis SunSet&lt;br /&gt;
  $solh      = $solh - ($sdiff * $sch);                                    # h bis SunSet - X&lt;br /&gt;
  $solh      = $solh &amp;lt; 0 ? 0 : $solh;&lt;br /&gt;
   &lt;br /&gt;
  my $ahrem  = ReadingsNum ($batdev, &#039;EnergyRemain&#039;, 0) / 48;              # Ah Bat bis SOC&lt;br /&gt;
  $ahrem     = sprintf &amp;quot;%.0f&amp;quot;, $ahrem;&lt;br /&gt;
  &lt;br /&gt;
  my $fcdiff = ($pvfc - $cofc) * $spcorr;     # Korrektur d. noch prognostizierten Überschussenergie &lt;br /&gt;
  $fcdiff    = $fcdiff &amp;lt; 0 ? 0 : $fcdiff;     # Wh&lt;br /&gt;
  &lt;br /&gt;
  my $loadcur = $maxcspc;&lt;br /&gt;
  &lt;br /&gt;
  if ($cpv &amp;amp;&amp;amp; $solh &amp;amp;&amp;amp; $ahrem &amp;amp;&amp;amp; $fcdiff &amp;gt; $ahrem) {  # Ladeanforderung und Überschuss übersteigt &lt;br /&gt;
                                                      # Lademenge&lt;br /&gt;
      my $cspc = sprintf &amp;quot;%.2f&amp;quot;, ($ahrem / $solh);    # A = Ah / h -&amp;gt; A Soll Schätzung&lt;br /&gt;
&lt;br /&gt;
      Log3 ($name, 3, qq{$name - userFn -&amp;gt; Battery charging process should be completed }.&lt;br /&gt;
                      qq{in &amp;gt;$solh&amp;lt; hours});&lt;br /&gt;
      Log3 ($name, 3, qq{$name - userFn -&amp;gt; raw Target charging current: $cspc});&lt;br /&gt;
	  &lt;br /&gt;
      $cspc = sprintf &amp;quot;%.2f&amp;quot;, ($cspc - $mppt1c);      # SmartLoader IST berücksichtigen&lt;br /&gt;
	  &lt;br /&gt;
      Log3 ($name, 3, qq{$name - userFn -&amp;gt; Charge Current minus MPPT load Current &amp;gt;$mppt1c&amp;lt;: $cspc});&lt;br /&gt;
	  &lt;br /&gt;
      $loadcur = $cspc &amp;lt;= 0       ? 0       :     # nur MPPT Ladung&lt;br /&gt;
                 $cspc &amp;lt;= $cclvl0 ? $cclvl0 :     # Übergangsbereich&lt;br /&gt;
                 $cspc &amp;lt;= $cclvl1 ? $cclvl1 :     # Ladung mit Level 1 Leistung&lt;br /&gt;
                 $cspc &amp;lt;= $cclvl2 ? $cclvl2 :     # Ladung mit Level 2 Leistung&lt;br /&gt;
                 $cspc &amp;lt;= $cclvl3 ? $cclvl3 :     # Ladung mit Level 3 Leistung&lt;br /&gt;
                 $maxcspc;                        # max. Ladesollstrom&lt;br /&gt;
	  &lt;br /&gt;
	  Log3 ($name, 3, qq{$name - userFn -&amp;gt; MaxChargeCurrent calculated: $loadcur});&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  readingsSingleUpdate ($hash, &#039;userFn_Bat_MaxChargeCurrent&#039;,       $loadcur.&#039; A&#039;,          1);&lt;br /&gt;
  readingsSingleUpdate ($hash, &#039;userFn_Bat_HoursUntilChargeFinish&#039;, sprintf (&amp;quot;%.2f&amp;quot;,$solh), 1);&lt;br /&gt;
  CommandSet           (undef, &amp;quot;$vebus MaxChargeCurrent $loadcur&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2023-05-03 201457.png|right|thumb|300px|Vorhersage PV Erzeugung und Energieverbrauch des (restlichen) Tages]]&lt;br /&gt;
Zunächst wird der am aktuellen Tag zu erwartende Totalüberschuss solarer Energie ermittelt. Das erfolgt aus der Differenz von &#039;&#039;RestOfDayPVforecast&#039;&#039; und &#039;&#039;RestOfDayConsumptionForecast&#039;&#039; unter Berücksichtigung eines Sicherheitsabschlages. Das Ergebnis liegt in Wh vor und wird bezogen auf 48 V (die Spannung des Batteriesystems) in Ah umgerechnet. &lt;br /&gt;
&lt;br /&gt;
Die noch benötigte Ladung der Batterie zur Erreichung des Soll SOC-Wertes ermittelt das ReadingsNum &#039;&#039;special_SunHours_Remain&#039;&#039; aus dem Batteriedevice, welches vom Modulreading &#039;&#039;currentBatteryDev&#039;&#039; ausgelesen wird.&lt;br /&gt;
&lt;br /&gt;
Sofern der so ermittelte solare Überschuss des (Rest)Tages die benötigte Lademenge der Batterie übersteigt, wird der DC Ladestrom so verringert, dass er sich in einem effizienten Bereich des MultiPlus II bewegt und dennoch rechnerisch ausreicht auf den Soll SOC-Wert zu laden.  &lt;br /&gt;
&lt;br /&gt;
Zu diesem Zweck wird im Modul über die Auswahl von &#039;&#039;SunHours_Remain&#039;&#039; im Attribut &#039;&#039;ctrlStatisticReadings&#039;&#039; das zusätzliche Reading &#039;&#039;special_SunHours_Remain&#039;&#039; erzeugt. Aus dem (noch) erforderlichen Ladungswert &#039;&#039;&#039;EnergyRemain&#039;&#039;&#039; (Ah) und der um eine Sicherheitszeit (&#039;&#039;Verkürzungsfaktor Zeit bis Vollladung vor Sunset&#039;&#039;) reduzierte Zeit bis zum Sonnenuntergang wird die rechnerisch erforderliche mindest Ladestromstärke ermittelt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dieser Wert wird auf die zu Anfang des Codeblocks definierten Ladelevel (&#039;&#039;Ladestrom Level X&#039;&#039;) abstrahiert und ein passender &#039;&#039;&#039;effizienter&#039;&#039;&#039; Ladestrom-Bereich ausgewählt.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2023-05-03 201719.png|right|thumb|300px|Vorhersage PV Erzeugung und Energieverbrauch des (restlichen) Tages]]&lt;br /&gt;
&lt;br /&gt;
In allen anderen Fällen, wenn z.B. rechnerisch nicht genügend oder keine Solarenergie erzeugt wird (Nachts) oder der Speicher gefüllt ist, wird der maximale (Sollwert) des Ladestroms &#039;&#039;$maxcspc = 35&#039;&#039; eingestellt. Dieser Wert entspricht dem maximalen Ladestrom gemäß Herstellerunterlagen Pylontech.&lt;br /&gt;
&lt;br /&gt;
Die Einstellung erfolgt per Set-Kommando im Victron vebus MQTT Device &#039;&#039;MQTT2_cerboGX_c0619ab34e08_vebus&#039;&#039;. Dieses Device wurde auch während der MQTT Intergration des Victron Systems angelegt und wird hier nicht näher diskutiert.&lt;br /&gt;
Zur Kontrolle des kalkulierten Wertes werden noch die Readings &#039;&#039;SolCast_userFn_MaxChargeCurrent&#039;&#039; im Batteriedevice und &#039;&#039;userFn_Bat_MaxChargeCurrent&#039;&#039; im SolarForecast Device generiert.&lt;br /&gt;
&lt;br /&gt;
Neben der Effizienzoptimierung hat dieses Verfahren auch den Vorteil einer möglichst schonenden Batterieaufladung was der Lebensdauer der Komponenten zugute kommen sollte.&lt;br /&gt;
&lt;br /&gt;
=== Poolheizung in Abhängigkeit von vorhandenem Photovoltaik-Überschuss aktivieren/deaktivieren (Eigenverbrauch optimieren) ===&lt;br /&gt;
Eine (Whirl-)Poolheizung soll bei ausreichend überschüssiger Energie aus einer Photovoltaikanlage dynamisch gesteuert werden (Eigenverbrauchsoptimierung). Im folgenden Beispiel ist ein Device mit der Bezeichnung &#039;&#039;Forecast&#039;&#039; des Typs &#039;&#039;SolarForecast bereits&#039;&#039; angelegt und konfiguriert. Ein freies Consumer-Attribut &#039;&#039;consumer01&#039;&#039; wird beispielhaft wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr Forecast consumer01 MQTT2_layzspa type=other power=1950 mode=can on=&amp;quot;heater on&amp;quot; off=&amp;quot;heater off&amp;quot; pcurr=WATT interruptable=1 swstate=heaterstate:1:0 auto=Automatiksteuerung mintime=SunPath spignorecond=EVCharger22:LadungMitPVUeberschussActive:1 icon=scene_pool notbefore=8 notafter=20&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Poolheizung ist innerhalb FHEM bereits im Device &#039;&#039;MQTT2_layzspa&#039;&#039; integriert und lässt sich normalerweise per FHEM-Befehl &amp;quot;set &#039;&#039;MQTT2_layzspa heater on&amp;quot;&#039;&#039; oder &#039;&#039;&amp;quot;set MQTT2_layzspa heater off&amp;quot;&#039;&#039; steuern. Entsprechend werden die Schlüssel-Wert-Paare &#039;&#039;&amp;quot;on=&amp;quot;&#039;&#039; und &#039;&#039;&amp;quot;off=&amp;quot;&#039;&#039; definiert. &lt;br /&gt;
&lt;br /&gt;
Der Stromverbrauch einer aktiven Poolheizung ist uns bekannt und wird im Schlüssel &#039;&#039;&amp;quot;power=1950&amp;quot;&#039;&#039; definiert. Die Heizfunktion soll nur bei ausreichend Überschuss aktiviert werden dürfen und muss bei Unterschreitung sofort abgeschaltet werden. Diese Eigenschaften werden über die Schlüssel &#039;&#039;&amp;quot;mode=can&amp;quot;&#039;&#039; und &#039;&#039;&amp;quot;interruptable=&amp;quot;1&amp;quot;&#039;&#039; festgelegt. Zuletzt soll grundsätzlich nur in der Zeit zwischen 08:00 Uhr bis 20:00 Uhr geheizt werden dürfen. &lt;br /&gt;
&lt;br /&gt;
Die Schlüssel &#039;&#039;&amp;quot;notbefore=8&amp;quot;&#039;&#039; und &#039;&#039;&amp;quot;notafter=20&amp;quot;&#039;&#039; legen diese Eigenschaften fest. Zur Anzeige des Schaltzustands der Heizung wurde der Schlüssel &#039;&#039;&amp;quot;swstate=heaterstate:1:0&amp;quot;&#039;&#039; hinzugefügt (Wert 1 = Heizung aktiv, Wert 0= Heizung aus). &lt;br /&gt;
&lt;br /&gt;
==== Priorisierung vor externen PV-Überschuss gesteuerten Verbrauchern ====&lt;br /&gt;
Der Schlüssel-Wert &#039;&#039;&#039;&amp;quot;spignorecond=&amp;quot;&#039;&#039;&#039; bietet optional die Möglichkeit, einen Consumer auch ohne ausreichend PV-Überschuss einzuschalten. Bei erfüllter Bedingung wird der Verbraucher entsprechend der Planung eingeschaltet auch wenn zu dem Zeitpunkt kein PV Überschuss vorliegt. Im obigen Beispiel existiert in der Haus-Elektroinstallation eine Elektroauto-Ladestation mit eigener (externer) dynamischer PV-gesteuerter Fahrzeugladung ohne Integration in &#039;&#039;SolarForecast&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
In Abhängigkeit von PV-Generatorleistung und Sonneneinstrahlung besteht manchmal eine Möglichkeit, dass der gesamte PV-Überschuss zur Fahrzeugladung genutzt wird. Das Modul SolarForecast würde entsprechend keinen (oder zu wenig) PV-Überschuss erkennen und den Consumer &#039;&#039;MQTT2_layzspa&#039;&#039; nicht aktivieren. &lt;br /&gt;
&lt;br /&gt;
Durch Verwendung von &#039;&#039;spignorecond=EVCharger22:LadungMitPVUeberschussActive:1&#039;&#039; wird die Poolheizung gegenüber der Ladestation jedoch priorisiert mit PV-Überschuss versorgt. In diesem Beispiel wird Consumer1 aktiviert, wenn die Ladestation &amp;quot;&#039;&#039;EVCharger22&#039;&#039;&amp;quot; sich im PV-Überschuss-Modus befindet &#039;&#039;&#039;und&#039;&#039;&#039; momentan ein Fahrzeug lädt. In der Folge würde der Hausstromverbrauch um ca. 1950 Watt steigen, die externe Fahrzeugladestation diese Änderung registrieren und die Fahrzeugladeleistung entsprechend verringern oder ganz abbrechen.&lt;br /&gt;
&lt;br /&gt;
=== Luftentfeuchter PV-Überschuss gesteuert mit externer Zwangs-Einschaltbedingung ===&lt;br /&gt;
Im folgenden Beispiel wird ein Luftentfeuchter normalerweise nur bei ausreichend PV-Überschuss Energie eingeschaltet (Eigenverbrauchsoptimierung), soll jedoch bei hoher Luftfeuchtigkeit zusätzlich aktiviert werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr Forecast SolarForecast ShellyPlug1 type=other power=300 mode=can on=on off=off pcurr=power:W interruptable=1 swstate=state:on:off mintime=SunPath locktime=900 notbefore=07 notafter=22 spignorecond=ESPEasy_ESP_Easy1_am2302_sensor:humidity:high icon=Ventilator_fett&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Das in FHEM bereits angelegte Device namens &#039;&#039;ShellyPlug1&#039;&#039; dient als Zwischenstecker zur Steuerung des Luftentfeuchters. Der Schlüsselwert &amp;quot;&#039;&#039;mintime=SunPath&#039;&#039;&amp;quot; definiert die zeitliche Einplanung von Sonnenauf- bis untergang. Jedoch soll das Gerät unter keinen Umständen in der Nacht eingeschaltet werden, was über die Schlüssel &#039;&#039;&amp;quot;notbefore=07&amp;quot;&#039;&#039; bzw. &#039;&#039;&amp;quot;notafter=22&amp;quot;&#039;&#039; festgelegt ist. Weiterhin wurde im Schlüssel &#039;&#039;&amp;quot;locktime=900&amp;quot;&#039;&#039; festgelegt, dass zwischen (möglichen) Ein- und Ausschaltintervallen wenigstens 15 Minuten Wartezeit vergehen soll.&lt;br /&gt;
&lt;br /&gt;
Der Schlüssel-Wert &#039;&#039;&#039;&amp;quot;spignorecond=&amp;quot;&#039;&#039;&#039; bietet optional die Möglichkeit, ein Consumer bei erfüllter Bedingung auch ohne ausreichend PV-Überschuss einzuschalten. In diesem Beispiel wird ein Raumluftsensor abgefragt. Bei Vorhandensein der Einschaltschwelle &amp;quot;high&amp;quot; aktiviert sich der Consumer zur geplanten Laufzeit zwischen 07:00 bis 22:00 Uhr solange, bis der Raumluftsensor einen abweichenden Wert meldet.&lt;br /&gt;
&lt;br /&gt;
=== PV-Vorhersage an evcc übertragen (PV-Überschussladen von E-Autos über steuerbare Wallboxen) ===&lt;br /&gt;
[https://evcc.io evcc] ist ein Energie-Management-System, mit dem u.a. Überschussladen von Elektroautos möglich ist. Hier ist beschreiben, wie die SolarForecast-Vorhersagedaten per API von evcc abgerufen werden.&lt;br /&gt;
Lege im SolarForecast-Device ein User-Reading mit dem Namen forecast_json an. Es wandelt die Forecast-Werte in JSON und ins UTC-Zeitformat um, so dass evcc die Daten einlesen kann. Der Code wird nur ausgeführt, wenn das Reading nextCycletime ein Event erzeugt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt; &lt;br /&gt;
forecast_json:nextCycletime.* {&lt;br /&gt;
    use strict;&lt;br /&gt;
    use warnings;&lt;br /&gt;
    use JSON;&lt;br /&gt;
    use DateTime;&lt;br /&gt;
    use DateTime::Format::Strptime;&lt;br /&gt;
   &lt;br /&gt;
    my $hour = 0;&lt;br /&gt;
    my $last_start_ts;    &lt;br /&gt;
    my @output;&lt;br /&gt;
    &lt;br /&gt;
    # Parser für Datum mit CET/CEST&lt;br /&gt;
    my $parser = DateTime::Format::Strptime-&amp;gt;new(&lt;br /&gt;
        pattern   =&amp;gt; &amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;,&lt;br /&gt;
        time_zone =&amp;gt; &amp;quot;Europe/Berlin&amp;quot;,&lt;br /&gt;
    );&lt;br /&gt;
    my $start_ts;&lt;br /&gt;
    &lt;br /&gt;
    # Alle NextHour-Daten durchsuchen (als Fallback zur Vermeidung einer Endlosschleife auf max. 100 Std. begrenzen)&lt;br /&gt;
    while ($hour &amp;lt; 100) {&lt;br /&gt;
        my $hour_str = sprintf(&amp;quot;NextHour%02d&amp;quot;, $hour);&lt;br /&gt;
        my $start_str = FHEM::SolarForecast::NexthoursVal(&amp;quot;$NAME&amp;quot;, $hour_str, &amp;quot;starttime&amp;quot;, &amp;quot;na&amp;quot;);&lt;br /&gt;
        my $pvfc = FHEM::SolarForecast::NexthoursVal(&amp;quot;$NAME&amp;quot;, $hour_str, &amp;quot;pvfc&amp;quot;, &amp;quot;na&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        # Schleife beenden, wenn keine Vorhersage-Werte mehr vorhanden sind&lt;br /&gt;
        last if $start_str eq &amp;quot;na&amp;quot; or $pvfc eq &amp;quot;na&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        $start_ts = $parser-&amp;gt;parse_datetime($start_str);  # Zeitzone und Sommer/Winterzeit berücksichtigen&lt;br /&gt;
&lt;br /&gt;
        # Zeit nach UTC und ISO 8601 konvertieren und Vorhersagewert ergänzen&lt;br /&gt;
        push @output, {&lt;br /&gt;
            start =&amp;gt; $start_ts-&amp;gt;set_time_zone(&amp;quot;UTC&amp;quot;)-&amp;gt;iso8601() . &amp;quot;Z&amp;quot;,&lt;br /&gt;
            end   =&amp;gt; $start_ts-&amp;gt;add(hours =&amp;gt; 1)-&amp;gt;set_time_zone(&amp;quot;UTC&amp;quot;)-&amp;gt;iso8601() . &amp;quot;Z&amp;quot;,&lt;br /&gt;
            value =&amp;gt; 0 + $pvfc,&lt;br /&gt;
        };&lt;br /&gt;
        $hour++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    # Prüfen, ob der letzte Wert 23 Uhr war -&amp;gt; zusätzliche Stunde anhängen, damit der Tag&lt;br /&gt;
    # bei evcc als vollständig angezeigt wird (siehe https://github.com/evcc-io/evcc/issues/22979)&lt;br /&gt;
    if ($start_ts-&amp;gt;hour == 23) {&lt;br /&gt;
&lt;br /&gt;
        # Zeit nach UTC und ISO 8601 konvertieren und Vorhersagewert ergänzen&lt;br /&gt;
        push @output, {&lt;br /&gt;
            start =&amp;gt; $start_ts-&amp;gt;set_time_zone(&amp;quot;UTC&amp;quot;)-&amp;gt;iso8601() . &amp;quot;Z&amp;quot;,&lt;br /&gt;
            end   =&amp;gt; $start_ts-&amp;gt;add(hours =&amp;gt; 1)-&amp;gt;set_time_zone(&amp;quot;UTC&amp;quot;)-&amp;gt;iso8601() . &amp;quot;Z&amp;quot;,&lt;br /&gt;
            value =&amp;gt; 0,&lt;br /&gt;
        };      &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    # Ausgabe als JSON&lt;br /&gt;
    my $json = JSON-&amp;gt;new-&amp;gt;utf8-&amp;gt;pretty-&amp;gt;encode(\@output);&lt;br /&gt;
    return $json;&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Datei:Screenshot 2025-08-04 104835.png|right|thumb|300px|Darstellung der PV-Vorhersage in evcc auf Basis der SolarForecast-Daten]]&lt;br /&gt;
&lt;br /&gt;
Soll der Code zur Erstellung des userReadings forecast_json in die 99_myUtils ausgelagert werden, erstelle die Funktion &#039;&#039;forecast_json&#039;&#039; mit ergänztem Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;	&lt;br /&gt;
  # - Perl Module laden&lt;br /&gt;
  use strict;&lt;br /&gt;
  use warnings;&lt;br /&gt;
  use JSON;&lt;br /&gt;
  use DateTime;&lt;br /&gt;
  use DateTime::Format::Strptime;&lt;br /&gt;
&lt;br /&gt;
  forecast_json {                   &amp;lt;--- ändern&lt;br /&gt;
    my $NAME = @_;                  &amp;lt;--- ergänzen&lt;br /&gt;
    my $hour = 0;&lt;br /&gt;
    my $last_start_ts;    &lt;br /&gt;
    my @output;&lt;br /&gt;
  ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;	&lt;br /&gt;
&lt;br /&gt;
Die Definition von userReadings in SolarForecast ändert sich zum Aufruf der Funktion in:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
userReadings forecast_json:nextCycletime.* { main::forecast_json($NAME) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Kommunikation läuft über den integrierten FHEM-Webserver, der die JSON-Daten aus dem Reading forecast_json veröffentlicht. Dazu wird in FHEM eine separate Webinstanz auf einem neuen Port erstellt, die ohne [[CsrfToken-HowTo|CSFR-Token]] (Achtung, Auswirkungen auf die Sicherheit beachten!) und nur von localhost aufrufbar ist (Voraussetzung: evcc läuft auf derselben Maschine wie FHEM):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Text&amp;quot;&amp;gt;&lt;br /&gt;
define WEBapi FHEMWEB 8089   ---&amp;gt;  (define WEBapi FHEMWEB IPV6:8089 global  bei Verwendung von IPV6)&lt;br /&gt;
attr WEBapi csrfToken none&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== evcc Integration ====&lt;br /&gt;
&#039;&#039;&#039;Konfiguration über die Datei evcc.yaml&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der [https://docs.evcc.io/docs/tariffs#pv-vorhersage evcc-Konfig unter tariffs] steht die Quelle für die Solar-Vorhersage. Der FHEM-Befehl {ReadingsVal(&#039;solarforecast_dev&#039;,&#039;forecast_json&#039;,&#039;[]&#039;)} wird encoded und in die uri eingetragen. Trage statt solarforecast_dev den passenden Namen deines SolarForecast-Device ein. evcc holt die Daten aus dem Reading forecast_json dann regelmäßig ab.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;yaml&amp;quot;&amp;gt;&lt;br /&gt;
solar:&lt;br /&gt;
  type: custom&lt;br /&gt;
  interval: 20m    &lt;br /&gt;
  forecast:&lt;br /&gt;
    source: http&lt;br /&gt;
    uri: http://localhost:8089/fhem?cmd=%7BReadingsVal%28%27solarforecast_dev%27%2C%27forecast_json%27%2C%27%5B%5D%27%29%7D&amp;amp;XHR=1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Konfiguration über den UI-Editor&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der aktuellen evcc-Version wird die Vorhersageintegration über den UI-Editor mit einer veränderten Syntax vorgenommen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
tariff: solar&lt;br /&gt;
forecast:&lt;br /&gt;
  source: http&lt;br /&gt;
  uri: http://localhost:8089/fhem?cmd=%7BReadingsVal%28%27solarforecast_dev%27%2C%27forecast_json%27%2C%27%5B%5D%27%29%7D&amp;amp;XHR=1&lt;br /&gt;
  jq: |&lt;br /&gt;
    map({&lt;br /&gt;
      &amp;quot;start&amp;quot;: .start,&lt;br /&gt;
      &amp;quot;end&amp;quot;: .end,&lt;br /&gt;
      &amp;quot;value&amp;quot;: .value&lt;br /&gt;
    }) | tostring&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zur Verbesserung der Sicherheit kann das neue WEBapi Device auch ein [[CsrfToken-HowTo#csrfToken festlegen|festes CSFR-Token]] verwenden. Dieses Token muss dann in der evcc-Konfiguration an die uri mittels &amp;amp;fwcsrf=&amp;lt;festes token&amp;gt; angehängt werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Poolsteuerung inkl. Eigenverbrauchsoptimierung und zusätzlichem Verbraucher, um Einspeiselimit zu vermeiden + manuelle Steuerung durch Sonderprogramme ===&lt;br /&gt;
&#039;&#039;&#039;Vorhandene Hardware:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Poolpumpe, die über mehrere Stufen verfügt. Hier werden zwei verwendet.&lt;br /&gt;
** Pump Low: Energiesparprogramm um den Pool umzuwälzen, auch wenn nicht genug PV Leistung zur Verfügung steht. -&amp;gt; ca. 250W&lt;br /&gt;
** Pump High: Normalbetrieb wenn genug PV Überschuss zur Verfügung steht. -&amp;gt; ca. 800W zusätzlich&lt;br /&gt;
* Poolheizung: Wärmepumpe -&amp;gt; ca. 1,5kW elektrisch&lt;br /&gt;
* Nachbars Pool: Pumpe + Salzanlage +pH-Regler -&amp;gt; ca. 650W&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Anforderungen:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Pool muss täglich mindestens 1x umgewälzt werden.&lt;br /&gt;
* Im Idealfall wird der Pool &amp;gt; 2x umgewälzt.&lt;br /&gt;
* Bei genügend Überschuss soll der Pool geheizt werden. Es soll nur Sonnenstrom für die Poolheizung verwendet werden.&lt;br /&gt;
* Um das Einspeiselimit zu vermeiden, soll auch geheizt werden, wenn der Pool schon warm genug ist. (&amp;gt;28,5 °C)&lt;br /&gt;
* Sollte trotzdem noch das Einspeiselimit erreicht werden, soll auch der Pool des Nachbarn versorgt werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Herausforderungen:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Verbraucher dürfen nur in einer gewissen Reihenfolge geschaltet werden, auch wenn der Überschuss eine andere Reihenfolge ergeben würde.&lt;br /&gt;
* Pumpe mit mehreren Stufen muss als zwei Consumer abgebildet werden, um die Schaltlogik in SolarForecast abzubilden. Würde die Trennung außerhalb von Solarforecast realisiert, könnte Solarforecast den Verbraucher schlechter &amp;quot;lernen&amp;quot;, denn dann wäre es ein Consumer mit ständig wechselndem Verbrauch.&lt;br /&gt;
* Pool des Nachbarn darf nicht laut der benötigten Leistung geschaltet werden, sondern in Abhängigkeit der Einspeisebegrenzung.&lt;br /&gt;
&lt;br /&gt;
In diesem Solarforcast-Device sind 16 Verbraucher definiert. Im Weiteren werden jedoch nur die verwendeten betrachtet. Da diese Reglung mittlerweile recht komplex ist, werden auch viele Dinge, die nicht SolarForcast betreffen, aber trotzdem dazu gehören, gezeigt. Es trägt zum Verständnis bei und man kann sich hier sicher Ideen holen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ergebnis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In den folgenden beiden Bildern sieht man das Regelverhalten recht gut.&lt;br /&gt;
[[Datei:Mustertag ohne Wolken.jpg|zentriert|mini|823x823px|Wolkenloser Tag]]&lt;br /&gt;
Hier erkennt man gut das Einschalten der jeweiligen Verbraucher (Pump Low, Pump High, Wärmepumpe und Nachbar Pool). Die Wärempumpe schaltet erst bei 5kW Überschuss ein, da der Pool eigentlich schon warm genug ist. Sie dient &amp;quot;nur&amp;quot; dazu, das EInspeiselimit zu verhindern.Auch das Auschalten ist wieder deutlich zu erkennen. Die Regleung folgt dem Überschuss recht gut. (Die Leistungsspitzen auf dem Plateau sind normale Großverbraucher im Haus.)&lt;br /&gt;
[[Datei:Wechselhaft.jpg|zentriert|mini|818x818px|Wechselhafter Tag.]]&lt;br /&gt;
In diesem Bild sieht man das &amp;quot;verzweifelte&amp;quot; Regeln um das wechselhafte Wetter auszugleichen. Hier gibt es keine korrekte Reaktion und es wird durch die Sperrzeiten und andere Delays versucht, ein zu häufiges hin- und herschalten möglichst zu vermeiden. In Summe aber auch bei so einem Wetter ein akzeptables Verhalten.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Definition der Consumer:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allgemeine Erklärungen zu den Definitionen:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;asynchron=0&#039;&#039;&#039;: Da hier die Werte des Überschusses für das Timing der Schaltvorgänge verwendet werden, darf hier keine Eventsteuerung verwendet werden. Sonst kann man nicht mehr sagen, über welchen Zeitraum der Mittelwert oder der Median gebildet wurde. Dafür wurde die Zykluszeit des SolarForecast-Device auf 60 Sekunden geändert, um die Überlegungen zu vereinfachen. Bei Event-Steuerung könnte man nicht sagen ob die letzten 10 Events in den letzten 5 Sekunden oder in den letzten 10 Minuten aufgetreten sind.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;power=xxx&#039;&#039;&#039;: Wurde teilweise etwas höher als der tatsächliche Wert gewählt, um nach dem Einschalten sicherzustellen, dass nicht sofort der gesamte Überschuss &amp;quot;verbraucht&amp;quot; wird und somit gleich wieder abgeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;auto=xxx&#039;&#039;&#039;: Jeder Verbraucher benötigt sein eigenes auto-Reading, da die Automatik für die Regelung in verschiedenen Stufen ein- und ausgeschaltet werden muss.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dum_valve&#039;&#039;&#039;: Dummy-Device in dem die Zustände der Regelung abgebildet werden. Notifys lesen bzw. befüllen diesen Dummy und steuern dann die Hardware bzw. wird der Dummy durch Werte aus der Hardware passend befüllt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;surpmeth=median_xx:&#039;&#039;&#039; Durch das asynchron=0 in allen Consumern und beim Generator wird von Solarforcast genau alle 60 Sekunden ein Zyklus ausgeführt. Das führt dazu, dass der Median genau über xx Minuten gebildet wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;locktime=xx:xx&#039;&#039;&#039;: Sicherheitsvorkehrung, dass nicht zu oft geschaltet werden kann. Schont die Hardware und verhindert ein Schwingen. Abhänging vom geschalteten Gerät. z.B. soll die Wärmepumpe möglichst wenig takten, um die Lebensdauer zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Es gibt dann auch noch einige weitere Sicherheitsvorkehrungen, um diese Regelung möglichst stabil und hardwareschonend zu gestalten. Die Schwierigkeit sind nicht die Bilderbuchtage mit einem glatten Verlauf der PV-Leistung, sondern Tage mit ständig wechselndem Überschuss in der Nähe der Schaltgrenzen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;swoncond= dum_valve:sf_true:{main::xxx_On}:&#039;&#039;&#039; Hier werden verschiedene Zustände geprüft, um ein Gerät nur dann einzuschalten, wenn es sinnvoll und sicher ist.&lt;br /&gt;
&lt;br /&gt;
Details unter &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;swoffcond= dum_valve:sf_true:{main::xxx_Off}&#039;&#039;&#039;: Hier werden verschiedene Zustände geprüft, um ein Gerät nur dann auszuschalten, wenn es sinnvoll und sicher ist.&lt;br /&gt;
&lt;br /&gt;
Details unter &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pump Low: (consumer01)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
dum_valve:Pool+Low&lt;br /&gt;
aliasshort=Low&lt;br /&gt;
asynchron=0&lt;br /&gt;
auto=pump_low_auto&lt;br /&gt;
icon=scene_pool&lt;br /&gt;
interruptable=0&lt;br /&gt;
mintime=SunPath:0:180&lt;br /&gt;
mode=must&lt;br /&gt;
noshow=0&lt;br /&gt;
notafter=08:00&lt;br /&gt;
off=&amp;quot;pump_low off&amp;quot;&lt;br /&gt;
on=&amp;quot;pump_low on&amp;quot;&lt;br /&gt;
pcurr=pump_low_power&lt;br /&gt;
power=250&lt;br /&gt;
surpmeth=median_13&lt;br /&gt;
switchdev=dum_valve&lt;br /&gt;
swoffcond=dum_valve:sf_true:{main::Check_Pump_Low_Off}&lt;br /&gt;
swoncond=dum_valve:sf_true:{main::Check_Pump_Low_On}&lt;br /&gt;
swstate=pump_low:on:off&lt;br /&gt;
type=other&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterungen:&lt;br /&gt;
&lt;br /&gt;
* Die Pumpe soll ab Sonnenaufgang, bis 180 Minuten nach Sonnenuntergang (mintime=SunPath:0:180), bei mindestens 250W Überschuss (power=250) gestartet werden.&lt;br /&gt;
* Die Pumpe muss spätestens um 8:00 eingeplant werden (notafter=08:00), um das Umwälzen auch bei Schlechtwetter zu garantieren.&lt;br /&gt;
* Die Pumpe muss gestartet werden (mode=must) sobald sie eingeplant ist.&lt;br /&gt;
* swoncond sorgt dafür, dass sie vor 8:00 nur bei genügend Überschuss gestartet wird, oder es 8:00 ist. swondcond ist mit der eigentlichen Einschaltbedingung (eingeplant und mode=must) UND verknüpft. -&amp;gt; siehe &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039;&lt;br /&gt;
* Überschuss wird auch in swoncond mit der gewählten Methode geprüft.&lt;br /&gt;
* Die Pumpe darf, wenn sie gestartet wurde, auch bei fehlendem Überschuss nicht mehr unterbrochen werden. (interruptable=0)&lt;br /&gt;
* Die Pumpe wird am Ende der Einplanung ausgeschaltet oder wenn swoffcond erfüllt ist. swoffcond wird true, wenn eine gewisse Wassermenge umgewälzt wurde oder die Sicherheitsbedingungen nicht (mehr) erfüllt sind. swoffcond ist mit der eigentlichen Ausschaltbedingung (Planung endet) ODER verknüpft. -&amp;gt; siehe &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039;&lt;br /&gt;
* {&#039;&#039;&#039;main::&#039;&#039;&#039;xxx} dient dazu, um die Funktion xxx in der 99_mySolarForecastUtils.pm aus Solarforecast erreichbar zu machen.&lt;br /&gt;
* dum_valve:sf_true ist ein Reading, das fix 1 ist und als Vergleichswert für den in Klammern folgenden Perlcode dient. Wenn dieses Reading und der Perlcode gleich sind (1==1), ist die swoncond bzw swoffcond erfüllt.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pump High: (consumer03)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
dum_valve:Pool+High&lt;br /&gt;
aliasshort=High&lt;br /&gt;
type=other power=1000 asynchron=0&lt;br /&gt;
auto=pump_high_auto&lt;br /&gt;
icon=scene_pool&lt;br /&gt;
pcurr=pump_high_power&lt;br /&gt;
switchdev=dum_valve&lt;br /&gt;
swstate=pump_high:on:off&lt;br /&gt;
mode=can&lt;br /&gt;
mintime=SunPath&lt;br /&gt;
on=&amp;quot;pump_high on&amp;quot;&lt;br /&gt;
off=&amp;quot;pump_high off&amp;quot;&lt;br /&gt;
surpmeth=median_5&lt;br /&gt;
noshow=0&lt;br /&gt;
locktime=180:300&lt;br /&gt;
interruptable=1&lt;br /&gt;
swoncond=dum_valve:sf_true:{main::Check_Pump_High_On}&lt;br /&gt;
swoffcond=dum_valve:sf_true:{main::Check_Pump_High_Off}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterungen:&lt;br /&gt;
&lt;br /&gt;
* Pump HIgh ist die selbe Pumpe, aber eine höhere Durchflussmenge&lt;br /&gt;
* Der Mehrverbrauch beträgt eigentlich 800W wird hier aber mit 1000W angegeben, um eine Hysterese von ca. 200W zu erreichen und damit ein schnelles Abschalten nach dem Einschalten zu verhindern.&lt;br /&gt;
* Diese Stufe wird nur bei genügend Überschuss aktiviert. (mode=can)&lt;br /&gt;
* Diese Stufe wird bei fehlendem Überschuss unterbrochen. (interruptable=1)&lt;br /&gt;
* Diese Stufe wird nur während Sonnenschein eingeplant. (mintime=SunPath)&lt;br /&gt;
* locktime sorgt dafür, dass bei schnell wechselnden Bedingungen, nicht ständig umgeschaltet wird. -&amp;gt; Schonung der Pumpe.&lt;br /&gt;
* swoncond und swoffcond -&amp;gt; siehe &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Heatpump: (consumer05)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
Pool_Strom_Heizung:Poolheizung&lt;br /&gt;
aliasshort=WP&lt;br /&gt;
type=other power=1800 asynchron=0&lt;br /&gt;
icon=sani_heating_heatpump&lt;br /&gt;
auto=heatpump_auto&lt;br /&gt;
pcurr=Pool_Pin32_monotonic_count_PowerCurrent:W&lt;br /&gt;
etotal=Pool_Pin32_monotonic_count_EnergyMeter:kWh&lt;br /&gt;
switchdev=dum_valve&lt;br /&gt;
swstate=heatpump:on:off&lt;br /&gt;
mode=can&lt;br /&gt;
locktime=600:600&lt;br /&gt;
mintime=SunPath&lt;br /&gt;
on=&amp;quot;heatpump on&amp;quot;&lt;br /&gt;
off=&amp;quot;heatpump off&amp;quot;&lt;br /&gt;
surpmeth=median_13&lt;br /&gt;
noshow=0&lt;br /&gt;
swoncond=dum_valve:sf_true:{main::CheckWPOn}&lt;br /&gt;
interruptable=1&lt;br /&gt;
swoffcond=dum_valve:sf_true:{main::CheckWPOff}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterungen:&lt;br /&gt;
&lt;br /&gt;
* Der Verbrauch ist hier wieder etwas zu hoch angegeben (1800W statt realen 1500W), um eine Hysterese zu erreichen.&lt;br /&gt;
* Da es sich hier um eine Wärmepumpe handelt, die nicht getaktet werden sollte, ist die locktime in beide Schaltrichtungen mit 10 Minuten relativ hoch.&lt;br /&gt;
* Die Ermittlung des Medians ist mit 13 Minuten recht lang, um den Überschuss über lange Zeit zu glätten, damit möglichst selten geschaltet wird. Diese 13 Minuten in Kombination mit der Locktime und der Hysterese führten bei dieser Anlage bisher dazu, dass höchstens 5 Zyklen am Tag geschaltet wurden. -&amp;gt; Hier kann das individuelle Schaltverhalten optimiert werden. Besseres Verfolgen des Überschusses vs. weniger Taktungen der Wärmepumpe.&lt;br /&gt;
* swoncond und swoffcond -&amp;gt; siehe &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nachbars Pool: (consumer07)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
Shelly_Plug_S_1:Kurz+Pool&lt;br /&gt;
aliasshort=Kurz&lt;br /&gt;
type=other power=650 asynchron=0&lt;br /&gt;
icon=scene_pool&lt;br /&gt;
auto=pool_kurz_auto&lt;br /&gt;
pcurr=power:W&lt;br /&gt;
switchdev=dum_valve&lt;br /&gt;
swstate=pool_kurz:on:off&lt;br /&gt;
mode=can&lt;br /&gt;
mintime=SunPath&lt;br /&gt;
on=&amp;quot;pool_kurz on&amp;quot;&lt;br /&gt;
off=&amp;quot;pool_kurz off&amp;quot;&lt;br /&gt;
surpmeth=median_13&lt;br /&gt;
noshow=0&lt;br /&gt;
interruptable=1&lt;br /&gt;
locktime=600:300&lt;br /&gt;
swoncond=dum_valve:sf_true:{main::Check_Pool_Kurz_On}&lt;br /&gt;
swoffcond=dum_valve:sf_true:{main::Check_Pool_Kurz_Off}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterungen:&lt;br /&gt;
&lt;br /&gt;
* Dieser Consumer dient als Einspeisebegrenzungsschutz und wird aktiviert, sobald sich der Überschuss der Einspeisegrenze nähert.  -&amp;gt; siehe &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039;&lt;br /&gt;
* Verbraucher kann recht träge geschaltet werden. (surpmeth=median_13 und locktime=600:300)&lt;br /&gt;
* Consumer wird ausgeschaltet wenn ein gewisser Überschuss unterschritten wird und somit die Einspeisegrenze wieder weit genug weg ist. -&amp;gt; siehe &#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039; &lt;br /&gt;
&#039;&#039;&#039;99_mySolarForecastUtils.pm&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Hier sind die Funktionen, die für diese Regelung verwendet werden, der Übersichtlichkeit halber in einzelnen Blöcken mit Erklärungen dargestellt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
package main;&lt;br /&gt;
use strict;&lt;br /&gt;
use warnings;&lt;br /&gt;
&lt;br /&gt;
my $pool_dummy = &#039;dum_valve&#039;;&lt;br /&gt;
my $pool_temperature = &#039;Pool_Temp&#039;;&lt;br /&gt;
my $flow_sensor = &#039;Pool_Pin_A0&#039;;&lt;br /&gt;
my $water_counter_l1 = &#039;pump_l1_hc&#039;;&lt;br /&gt;
my $water_counter_l2 = &#039;pump_l2_hc&#039;;&lt;br /&gt;
my $target_temp = 28.4; # maximum temperature for heating, without infeed limit&lt;br /&gt;
my $pool_kurz_sw_hofb = &#039;PwSw_Schalter&#039;; # Homematic switch at pool neighbour&lt;br /&gt;
my $pool_kurz_sw_kurz = &#039;Shelly_Plug_S_1&#039;; # Shelly switch for pool Kurz at home&lt;br /&gt;
&lt;br /&gt;
my $pump_low_id			= sprintf &amp;quot;%02d&amp;quot;, 1;&lt;br /&gt;
my $pump_high_id		= sprintf &amp;quot;%02d&amp;quot;, 3;&lt;br /&gt;
my $heatpump_id			= sprintf &amp;quot;%02d&amp;quot;, 5;&lt;br /&gt;
my $pool_kurz_id		= sprintf &amp;quot;%02d&amp;quot;, 7;&lt;br /&gt;
&lt;br /&gt;
my $switch_delay = 160; # just under three minutes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub&lt;br /&gt;
SolarForecastUtils_Initialize($$)&lt;br /&gt;
{&lt;br /&gt;
  my ($hash) = @_;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Hier werden die IDs der Geräte definiert, um über sprechende Namen darauf zugreifen zu können.&lt;br /&gt;
* Einige Devices und Parameter, die immer wieder gebraucht werden sind hier angegeben.&lt;br /&gt;
* sprintf wird verwendet um sicherzustellen, dass die IDs zweistellig sind. z.B. 3 -&amp;gt; 03&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pump Low&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
###################&lt;br /&gt;
### Pumpe - LOW ###&lt;br /&gt;
###################&lt;br /&gt;
&lt;br /&gt;
sub&lt;br /&gt;
Check_Pump_Low_On{&lt;br /&gt;
my $name = &#039;energy_mgmt&#039;;&lt;br /&gt;
my $surplus	= FHEM::SolarForecast::ConsumerVal ($name,$pump_low_id,&#039;surpmethResult&#039;,&#039;&#039;);&lt;br /&gt;
my $nom_power	= FHEM::SolarForecast::ConsumerVal ($name,$pump_low_id,&#039;power&#039;,&#039;&#039;);&lt;br /&gt;
my ($min, $hour) = (localtime())[1,2];&lt;br /&gt;
my $timer = 0;&lt;br /&gt;
if($hour &amp;gt; 8 || ($hour == 8 &amp;amp;&amp;amp; $min &amp;gt;= 0)){$timer=1;}&lt;br /&gt;
&lt;br /&gt;
if(ReadingsVal($pool_dummy,&amp;quot;valve_position&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;normal&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&amp;quot;special_function&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;none&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; ($surplus &amp;gt; $nom_power&lt;br /&gt;
		|| $timer&lt;br /&gt;
	)&lt;br /&gt;
)&lt;br /&gt;
	{&lt;br /&gt;
	return 1;}&lt;br /&gt;
else&lt;br /&gt;
	{&lt;br /&gt;
	return 0;}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub&lt;br /&gt;
Check_Pump_Low_Off{&lt;br /&gt;
my $bath_mode = ReadingsVal($pool_dummy,&amp;quot;bath_mode&amp;quot;,0);&lt;br /&gt;
my $m3_l1 = ReadingsVal($water_counter_l1,&amp;quot;waterAmount&amp;quot;,0);&lt;br /&gt;
my $m3_l2 = ReadingsVal($water_counter_l2,&amp;quot;waterAmount&amp;quot;,0);&lt;br /&gt;
my $water_volume = AttrVal($pool_dummy,&amp;quot;water_volume&amp;quot;,42); #42m³&lt;br /&gt;
my $desired_cf_l1 = AttrVal($pool_dummy,&amp;quot;desired_cf_l1&amp;quot;,0); #circulation_factor_level1&lt;br /&gt;
my $desired_cf_l2 = AttrVal($pool_dummy,&amp;quot;desired_cf_l2&amp;quot;,0); #circulation_factor_level2&lt;br /&gt;
my $bathmode_factor = AttrVal($pool_dummy,&amp;quot;bathmode_factor&amp;quot;,1);&lt;br /&gt;
my $desired_amount_l1;&lt;br /&gt;
my $desired_amount_l2;&lt;br /&gt;
my $amount = $m3_l1 + $m3_l2;&lt;br /&gt;
if($bath_mode == 1){&lt;br /&gt;
	$desired_amount_l1 = $desired_cf_l1 * $water_volume;&lt;br /&gt;
	$desired_amount_l2 = $desired_cf_l2 * $water_volume;&lt;br /&gt;
}else{&lt;br /&gt;
	$desired_amount_l1 = $desired_cf_l1 * $water_volume/$bathmode_factor;&lt;br /&gt;
	$desired_amount_l2 = $desired_cf_l2 * $water_volume/$bathmode_factor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if(($amount &amp;gt; $desired_amount_l1)&lt;br /&gt;
	&amp;amp;&amp;amp; (ReadingsVal($pool_dummy,&amp;quot;pump_high&amp;quot;,&amp;quot;on&amp;quot;) eq &amp;quot;off&amp;quot;  &amp;amp;&amp;amp; ReadingsAge($pool_dummy,&amp;quot;pump_high&amp;quot;,0) &amp;gt;160)&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&amp;quot;special_function&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;none&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&amp;quot;valve_position&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;normal&amp;quot;&lt;br /&gt;
)&lt;br /&gt;
	{&lt;br /&gt;
		return 1;&lt;br /&gt;
	}else{&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Einschalten:&lt;br /&gt;
&lt;br /&gt;
* Es wird der errechnete Wert für den Überschuss von SolarForecast verwendet und auch der benötigte Überschuss aus dem Consumer ausgelesen.&lt;br /&gt;
* Das Einschalten wird erst durch erfolgreiche Prüfung der Hardwarevoraussetzungen erlaubt. -&amp;gt; Das Motorventil steht richtig und es ist kein Sonderbetrieb (Reinigung, Massage, Winter, o.ä.) aktiv.&lt;br /&gt;
* Es muss entweder genügend Überschuss vorhanden sein oder es ist 8:00.&lt;br /&gt;
&lt;br /&gt;
Ausschalten:&lt;br /&gt;
&lt;br /&gt;
* Wenn der Badebetrieb aktiv ist (bath_mode==1, [bei Außentemperatur &amp;gt; 24°C]) wird nach 90m³ Gesamtumwälzung ausgeschaltet.&lt;br /&gt;
* Wenn der Badebetrieb nicht aktiv ist (bath_mode==0, [bei Außentemperatur &amp;lt; 20°C]) wird bereits nach 42m³ Gesamtumwälzung ausgeschaltet.&lt;br /&gt;
* Prüfung, ob Pump High schon aus ist. Sollte durch die Logik gar nicht möglich sein, aber es könnte manuell oder durch einen (Logik-)Fehler trotzdem eingeschaltet sein.&lt;br /&gt;
* Prüfung, ob alle Hardware-Funktionen in einem für die Automatik geeigneten Zustand sind.&lt;br /&gt;
* Es wird auch geprüft, ob Pump High seit mindestens 3 Minuten aus ist, um zu verhindern, dass wegen fehlendem Überschuss gleich mehrere Geräte ausgeschaltet werden.&lt;br /&gt;
* Da die Zykluszeit 60 Sekunden ist, führen die 160 Sekunden dazu, dass nach drei Minuten(180 Sekunden) ein definierter Wert gilt. Mit 180 Sekunden könnte es manchaml eine Minute mehr sein.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pump High&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
####################&lt;br /&gt;
### Pumpe - HIGH ###&lt;br /&gt;
####################&lt;br /&gt;
&lt;br /&gt;
sub&lt;br /&gt;
Check_Pump_High_On{&lt;br /&gt;
my $bath_mode = ReadingsVal($pool_dummy,&amp;quot;bath_mode&amp;quot;,0);&lt;br /&gt;
my $m3_l1 = ReadingsVal($water_counter_l1,&amp;quot;waterAmount&amp;quot;,0);&lt;br /&gt;
my $m3_l2 = ReadingsVal($water_counter_l2,&amp;quot;waterAmount&amp;quot;,0);&lt;br /&gt;
my $water_volume = AttrVal($pool_dummy,&amp;quot;water_volume&amp;quot;,42); #42m³&lt;br /&gt;
my $desired_cf_l1 = AttrVal($pool_dummy,&amp;quot;desired_cf_l1&amp;quot;,0); #circulation_factor_level1&lt;br /&gt;
my $desired_cf_l2 = AttrVal($pool_dummy,&amp;quot;desired_cf_l2&amp;quot;,0); #circulation_factor_level2&lt;br /&gt;
my $bathmode_factor = AttrVal($pool_dummy,&amp;quot;bathmode_factor&amp;quot;,1);&lt;br /&gt;
my $desired_amount_l1;&lt;br /&gt;
my $desired_amount_l2;&lt;br /&gt;
my $amount = $m3_l1 + $m3_l2;&lt;br /&gt;
if($bath_mode == 1){&lt;br /&gt;
	$desired_amount_l1 = $desired_cf_l1 * $water_volume;&lt;br /&gt;
	$desired_amount_l2 = $desired_cf_l2 * $water_volume;&lt;br /&gt;
}else{&lt;br /&gt;
	$desired_amount_l1 = $desired_cf_l1 * $water_volume/$bathmode_factor;&lt;br /&gt;
	$desired_amount_l2 = $desired_cf_l2 * $water_volume/$bathmode_factor;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if(($amount &amp;lt; $desired_amount_l2)&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&amp;quot;special_function&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;none&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&amp;quot;valve_position&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;normal&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; (ReadingsVal($pool_dummy,&amp;quot;pump_low&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot;  &amp;amp;&amp;amp; ReadingsAge($pool_dummy,&amp;quot;pump_low&amp;quot;,0) &amp;gt; $switch_delay)&lt;br /&gt;
)&lt;br /&gt;
	{return 1}&lt;br /&gt;
else&lt;br /&gt;
	{return 0}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub&lt;br /&gt;
Check_Pump_High_Off{&lt;br /&gt;
my $bath_mode = ReadingsVal($pool_dummy,&amp;quot;bath_mode&amp;quot;,0);&lt;br /&gt;
my $m3_l1 = ReadingsVal($water_counter_l1,&amp;quot;waterAmount&amp;quot;,0);&lt;br /&gt;
my $m3_l2 = ReadingsVal($water_counter_l2,&amp;quot;waterAmount&amp;quot;,0);&lt;br /&gt;
my $water_volume = AttrVal($pool_dummy,&amp;quot;water_volume&amp;quot;,42); #42m³&lt;br /&gt;
my $desired_cf_l1 = AttrVal($pool_dummy,&amp;quot;desired_cf_l1&amp;quot;,0); #circulation_factor_level1&lt;br /&gt;
my $desired_cf_l2 = AttrVal($pool_dummy,&amp;quot;desired_cf_l2&amp;quot;,0); #circulation_factor_level2&lt;br /&gt;
my $bathmode_factor = AttrVal($pool_dummy,&amp;quot;bathmode_factor&amp;quot;,1);&lt;br /&gt;
my $desired_amount_l1;&lt;br /&gt;
my $desired_amount_l2;&lt;br /&gt;
my $amount = $m3_l1 + $m3_l2;&lt;br /&gt;
&lt;br /&gt;
if($bath_mode == 1){&lt;br /&gt;
	$desired_amount_l1 = $desired_cf_l1 * $water_volume;&lt;br /&gt;
	$desired_amount_l2 = $desired_cf_l2 * $water_volume;&lt;br /&gt;
}else{&lt;br /&gt;
	$desired_amount_l1 = $desired_cf_l1 * $water_volume/$bathmode_factor;&lt;br /&gt;
	$desired_amount_l2 = $desired_cf_l2 * $water_volume/$bathmode_factor;&lt;br /&gt;
}&lt;br /&gt;
if(($amount &amp;gt; $desired_amount_l2)&lt;br /&gt;
	&amp;amp;&amp;amp; (ReadingsVal($pool_dummy,&amp;quot;heatpump&amp;quot;,&amp;quot;on&amp;quot;) eq &amp;quot;off&amp;quot;  &amp;amp;&amp;amp; ReadingsAge($pool_dummy,&amp;quot;heatpump&amp;quot;,0) &amp;gt;160)&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&amp;quot;special_function&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;none&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&amp;quot;valve_position&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;normal&amp;quot;&lt;br /&gt;
)&lt;br /&gt;
	{return 1}&lt;br /&gt;
else&lt;br /&gt;
	{return 0}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Einschalten:&lt;br /&gt;
&lt;br /&gt;
* Prüfung, ob die gewünschte Umwälzung bezüglich des Badebetriebs noch nicht erreicht wurde.&lt;br /&gt;
* Prüfung der Hardwarevoraussetzungen.&lt;br /&gt;
* Prüfung, ob Pump Low schon seit mindestens drei Minuten aktiv ist. (sollte eigentlich immer der Fall sein, wenn die Automatik für Pump High aktiv ist)&lt;br /&gt;
&lt;br /&gt;
Ausschalten:&lt;br /&gt;
&lt;br /&gt;
* Prüfung, ob die gewünschte Umwälzung bezüglich des Badebetriebs bereits erreicht wurde.&lt;br /&gt;
* Prüfung der Hardwarevoraussetzungen.&lt;br /&gt;
* Prüfung, ob die Wärmepumpe schon seit mindestens drei Minuten aus ist. Ermöglicht drei Minuten lang, den Median für den Überschuss zu aktualisieren.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wärmepumpe&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
##################&lt;br /&gt;
### Wärempumpe ###&lt;br /&gt;
##################&lt;br /&gt;
sub&lt;br /&gt;
CheckWPOn(){&lt;br /&gt;
my $name = &#039;energy_mgmt&#039;;&lt;br /&gt;
my $surplus_on = 5000; # minimum surplus to avoid infeed limit with heatpump&lt;br /&gt;
my $surplus_restart = 3000; # minimum surplus to re-enable heatpump, when avoidung infeed limit and a big consumer turned the hp off&lt;br /&gt;
&lt;br /&gt;
my $planstate = FHEM::SolarForecast::ConsumerVal ($name,$heatpump_id,&#039;planstate&#039;,&#039;&#039;);&lt;br /&gt;
my $surplus	= FHEM::SolarForecast::ConsumerVal ($name,$heatpump_id,&#039;surpmethResult&#039;,&#039;&#039;);&lt;br /&gt;
if ($planstate =~ /^([^:]+)/) {&lt;br /&gt;
	$planstate = $1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if(ReadingsVal($flow_sensor,&amp;quot;reading&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; (ReadingsVal($pool_dummy,&amp;quot;special_function&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;none&amp;quot;&lt;br /&gt;
		|| ReadingsVal($pool_dummy,&amp;quot;special_function&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;party&amp;quot;&lt;br /&gt;
	)&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&#039;heat_protection&#039;,&#039;on&#039;) eq &amp;quot;off&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; ReadingsVal($pool_dummy,&amp;quot;valve_position&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;normal&amp;quot;&lt;br /&gt;
	&amp;amp;&amp;amp; (ReadingsVal($pool_dummy,&amp;quot;pump_high&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot;  &amp;amp;&amp;amp; ReadingsAge($pool_dummy,&amp;quot;pump_high&amp;quot;,0) &amp;gt; $switch_delay)&lt;br /&gt;
	&amp;amp;&amp;amp; (ReadingsVal($pool_temperature,&amp;quot;temperature&amp;quot;,30) &amp;lt; $target_temp &lt;br /&gt;
		|| (ReadingsVal($pool_temperature,&amp;quot;temperature&amp;quot;,15) &amp;gt;= $target_temp&lt;br /&gt;
			&amp;amp;&amp;amp; ( $surplus &amp;gt; $surplus_on&lt;br /&gt;
				|| (($planstate eq &amp;quot;replanned&amp;quot;) &amp;amp;&amp;amp; ($surplus &amp;gt; $surplus_restart))&lt;br /&gt;
			)&lt;br /&gt;
		)&lt;br /&gt;
	)&lt;br /&gt;
)&lt;br /&gt;
	{return 1}&lt;br /&gt;
else&lt;br /&gt;
	{return 0}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub&lt;br /&gt;
CheckWPOff{&lt;br /&gt;
my $name = &#039;energy_mgmt&#039;;&lt;br /&gt;
my $surplus_off = 1000; #minimum surplus to keep heatpump on, when avoiding infeed limit&lt;br /&gt;
&lt;br /&gt;
my $surplus	= FHEM::SolarForecast::ConsumerVal ($name,$heatpump_id,&#039;surpmethResult&#039;,&#039;&#039;);&lt;br /&gt;
if((ReadingsVal($flow_sensor,&amp;quot;reading&amp;quot;,&amp;quot;on&amp;quot;) eq &amp;quot;off&amp;quot;&lt;br /&gt;
	|| !((ReadingsVal($pool_dummy,&amp;quot;special_function&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;none&amp;quot;) &lt;br /&gt;
		|| (ReadingsVal($pool_dummy,&amp;quot;special_function&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;party&amp;quot;)&lt;br /&gt;
	)&lt;br /&gt;
	|| ReadingsVal($pool_dummy,&#039;heat_protection&#039;,&#039;off&#039;) eq &amp;quot;on&amp;quot;&lt;br /&gt;
	|| ReadingsVal($pool_dummy,&amp;quot;valve_position&amp;quot;,&amp;quot;&amp;quot;) ne &amp;quot;normal&amp;quot;&lt;br /&gt;
	|| ((ReadingsVal($pool_temperature,&amp;quot;temperature&amp;quot;,15) &amp;gt; $target_temp)&lt;br /&gt;
		&amp;amp;&amp;amp; ($surplus &amp;lt; $surplus_off)&lt;br /&gt;
		)&lt;br /&gt;
	)&lt;br /&gt;
	&amp;amp;&amp;amp; (ReadingsVal($pool_dummy,&amp;quot;heatpump&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot;  &amp;amp;&amp;amp; ReadingsAge($pool_dummy,&amp;quot;heatpump&amp;quot;,0) &amp;gt; $switch_delay)&lt;br /&gt;
)&lt;br /&gt;
	{return 1}&lt;br /&gt;
else&lt;br /&gt;
	{return 0}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Einschalten:&lt;br /&gt;
&lt;br /&gt;
* Prüfung, ob Flussensor ein. (Pool_pin_A0) -&amp;gt; Wasser fließt durch die Wärmepumpe.&lt;br /&gt;
* Prüfung, ob Pool in Normal- oder Partybetrieb ist und das Ventil in Normalposition ist. In beiden Fällen läuft Pump High.&lt;br /&gt;
* Einschalten wenn genug Überschuss da ist und die Temperatur &amp;lt;28.4°C ist oder wenn über 5000W Überschuss (Einspeisebegrenzung bei 5900W) da ist, egal wie warm der Pool ist.&lt;br /&gt;
* Sonderfall: Wenn die Wärmepumpe durch einen/mehrere Großverbrucher &amp;quot;kurz&amp;quot; ausgeschaltet wurde (swoffcond) wird sie ausgeplant. Ein Notify plant sie wieder ein. Wenn das passiert, soll die Wärmepumpe aber wieder bei 3000W Überschuss gestartet werden, um die Energie noch weiter zu nutzen bis der Überschuss unter 1000W fällt. (Hysterese von 500W, da die WP nur 1500W braucht)&lt;br /&gt;
&lt;br /&gt;
Ausschalten:&lt;br /&gt;
&lt;br /&gt;
* Ausschalten sobald hardwaremäßig irgendetwas faul ist. (Betriebsart, Ventilstellung, Durchfluss)&lt;br /&gt;
* Ausschalten wenn kein Überschuss. (interruptable=1)&lt;br /&gt;
* Wenn Wassertemperatur über 28,5°C und der Überschuss kleiner als 1000W ist.&lt;br /&gt;
* Nur schalten, wenn Wärmepumpe läuft und seit mindestens drei Minuten läuft (Sicherheit). Das verhindert das erneute Triggern des Notifys, wenn die Pumpe schon aus ist. Sollte nicht passieren, aber sicher ist sicher.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nachbar Pool&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
###################&lt;br /&gt;
### Pool - KURZ ###&lt;br /&gt;
###################&lt;br /&gt;
sub&lt;br /&gt;
Check_Pool_Kurz_On{&lt;br /&gt;
my $name = &#039;energy_mgmt&#039;;&lt;br /&gt;
my $surplus	= FHEM::SolarForecast::ConsumerVal ($name,$pool_kurz_id,&#039;surpmethResult&#039;,&#039;&#039;);&lt;br /&gt;
if(($surplus &amp;gt; 3000)&lt;br /&gt;
	&amp;amp;&amp;amp; ((ReadingsVal($pool_dummy,&amp;quot;heatpump&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot;  &amp;amp;&amp;amp; ReadingsAge($pool_dummy,&amp;quot;heatpump&amp;quot;,0) &amp;gt;160) || ReadingsVal($pool_dummy,&#039;heat_protection&#039;,&#039;off&#039;) eq &#039;on&#039; ))&lt;br /&gt;
	{return 1}&lt;br /&gt;
else&lt;br /&gt;
	{return 0}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub&lt;br /&gt;
Check_Pool_Kurz_Off{&lt;br /&gt;
my $name = &#039;energy_mgmt&#039;;&lt;br /&gt;
my $surplus	= FHEM::SolarForecast::ConsumerVal ($name,$pool_kurz_id,&#039;surpmethResult&#039;,&#039;&#039;);&lt;br /&gt;
if(($surplus &amp;lt; 1000 )&lt;br /&gt;
	&amp;amp;&amp;amp; (ReadingsVal($pool_dummy,&amp;quot;pool_kurz&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot;  &amp;amp;&amp;amp; ReadingsAge($pool_dummy,&amp;quot;pool_kurz&amp;quot;,0) &amp;gt;160))&lt;br /&gt;
	{return 1}&lt;br /&gt;
else&lt;br /&gt;
	{return 0}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Einschalten:&lt;br /&gt;
&lt;br /&gt;
* Überschuss ist nahe der Einspeisegrenze (5900W) und Wärmepumpe läuft seit mindestens drei Minuten. Es wird schon bei 3000W eingeschaltet, um dem Nachbarn etwas Gutes zu tun ;-)&lt;br /&gt;
&lt;br /&gt;
Ausschalten:&lt;br /&gt;
&lt;br /&gt;
* Überschuss ist unter 1000W. -&amp;gt; Um noch Reserven für den eigenen Verbrauch zu haben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hilfsfunktionen&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ctrlUserExitFn&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Hier erfolgt nach jedem Zyklus die Festlegung der verschiedenen Automatikmodi.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
#############################################################&lt;br /&gt;
##################### Exit Function #########################&lt;br /&gt;
#############################################################&lt;br /&gt;
my $ctrl_dummy	= &amp;quot;dum_valve&amp;quot;; # dummy device for pool-control&lt;br /&gt;
my $automatic	= ReadingsNum($ctrl_dummy,&amp;quot;sf_automatic&amp;quot;,1);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if($automatic){&lt;br /&gt;
&lt;br /&gt;
	my $pump_low_state = ReadingsVal($ctrl_dummy,&#039;pump_low&#039;,&#039;on&#039;);&lt;br /&gt;
	my $pump_low_auto	= FHEM::SolarForecast::ConsumerVal ($name, $pump_low_id, &#039;auto&#039;, &#039;&#039;);	# Automatikmodus der Pumpe&lt;br /&gt;
&lt;br /&gt;
	my $pump_high_state = ReadingsVal($ctrl_dummy,&#039;pump_high&#039;,&#039;on&#039;);&lt;br /&gt;
	my $pump_high_auto	= FHEM::SolarForecast::ConsumerVal ($name, $pump_high_id, &#039;auto&#039;, &#039;&#039;);	# Automatikmodus der Pumpe&lt;br /&gt;
&lt;br /&gt;
	my $heatpump_state = ReadingsVal($ctrl_dummy,&#039;heatpump&#039;,&#039;on&#039;);&lt;br /&gt;
	my $heatpump_auto	= FHEM::SolarForecast::ConsumerVal ($name, $heatpump_id, &#039;auto&#039;, &#039;&#039;);	# Automatikmodus der Wärmepumpe&lt;br /&gt;
	my $pool_heat_protection = ReadingsVal($ctrl_dummy,&#039;heat_protection&#039;,&#039;on&#039;);&lt;br /&gt;
&lt;br /&gt;
	my $pool_kurz_state = ReadingsVal($ctrl_dummy,&#039;pool_kurz&#039;,&#039;on&#039;);&lt;br /&gt;
	my $pool_kurz_auto	= FHEM::SolarForecast::ConsumerVal ($name, $pool_kurz_id, &#039;auto&#039;, &#039;&#039;);	# Automatikmodus des Pools&lt;br /&gt;
&lt;br /&gt;
	my $pump_low_delay	= FHEM::SolarForecast::ConsumerVal ($name, $pump_low_id, &#039;surpmeth&#039;, &#039;&#039;);&lt;br /&gt;
	if ($pump_low_delay =~ /_(\d+)/) {&lt;br /&gt;
    	$pump_low_delay = int(($1/2 + 1) * 60);&lt;br /&gt;
		Log3 (&amp;quot;SolarForecast&amp;quot;, 1, &amp;quot;SolarForecast: pump_low_delay: $pump_low_delay&amp;quot;);&lt;br /&gt;
	} else {&lt;br /&gt;
    	$pump_low_delay = 220;&lt;br /&gt;
		Log3 (&amp;quot;SolarForecast&amp;quot;, 1, &amp;quot;SolarForecast: warning - surpmeth for pump_low is: $pump_low_delay, but must be given as method_number, using fallback value&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	my $pump_high_delay	= FHEM::SolarForecast::ConsumerVal ($name, $pump_high_id, &#039;surpmeth&#039;, &#039;&#039;);&lt;br /&gt;
	if ($pump_high_delay =~ /_(\d+)/) {&lt;br /&gt;
    	$pump_high_delay = int(($1/2 + 1) * 60);&lt;br /&gt;
	} else {&lt;br /&gt;
    	$pump_high_delay = 160;&lt;br /&gt;
		Log3 (&amp;quot;SolarForecast&amp;quot;, 1, &amp;quot;SolarForecast: warning - surpmeth for pump_high is: $pump_high_delay, but must be given as method_number, using fallback value&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	my $heatpump_delay	= FHEM::SolarForecast::ConsumerVal ($name, $heatpump_id, &#039;surpmeth&#039;, &#039;&#039;);&lt;br /&gt;
	if ($heatpump_delay =~ /_(\d+)/) {&lt;br /&gt;
    	$heatpump_delay = int(($1/2 + 1) * 60);&lt;br /&gt;
	} else {&lt;br /&gt;
    	$heatpump_delay = 290;&lt;br /&gt;
		Log3 (&amp;quot;SolarForecast&amp;quot;, 1, &amp;quot;SolarForecast: warning - surpmeth for heatpump is: $heatpump_delay, but must be given as method_number, using fallback value&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	my $pool_kurz_delay	= FHEM::SolarForecast::ConsumerVal ($name, $pool_kurz_id, &#039;surpmeth&#039;, &#039;&#039;);&lt;br /&gt;
	if ($pool_kurz_delay =~ /_(\d+)/) {&lt;br /&gt;
    	$pool_kurz_delay = int(($1/2 + 1) * 60);&lt;br /&gt;
	} else {&lt;br /&gt;
    	$pool_kurz_delay = 160;&lt;br /&gt;
		Log3 (&amp;quot;SolarForecast&amp;quot;, 1, &amp;quot;SolarForecast: warning - surpmeth for pool_kurz is: $pool_kurz_delay, but must be given as method_number&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
############################&lt;br /&gt;
# Überhitzungsschutz aktiv #&lt;br /&gt;
############################&lt;br /&gt;
&lt;br /&gt;
if($pool_heat_protection eq &#039;on&#039;){&lt;br /&gt;
	if($heatpump_auto == 1){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy heatpump_auto 0&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	if($heatpump_state eq &amp;quot;on&amp;quot;){&lt;br /&gt;
			fhem(&amp;quot;set $ctrl_dummy heatpump off&amp;quot;)&lt;br /&gt;
	}&lt;br /&gt;
	#################&lt;br /&gt;
	#### on-chain ###&lt;br /&gt;
	#################&lt;br /&gt;
	if($pump_low_state eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;pump_low&#039;,0) &amp;gt; $pump_high_delay &amp;amp;&amp;amp; $pump_high_auto == 0  &amp;amp;&amp;amp; $pool_kurz_auto == 0){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pump_high_auto 1&amp;quot;);&lt;br /&gt;
	}elsif($pump_high_state eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;pump_high&#039;,0) &amp;gt; $pool_kurz_delay &amp;amp;&amp;amp; $pool_kurz_auto == 0 &amp;amp;&amp;amp; $pump_high_auto == 1){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pool_kurz_auto 1&amp;quot;);&lt;br /&gt;
	}elsif($pool_kurz_state eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; $pool_kurz_auto == 1 &amp;amp;&amp;amp; $pump_high_auto == 1){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pump_high_auto 0&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	#################&lt;br /&gt;
	### off-chain ###&lt;br /&gt;
	#################&lt;br /&gt;
	if($pool_kurz_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;pool_kurz&#039;,0) &amp;gt; $pump_high_delay &amp;amp;&amp;amp; $pool_kurz_auto == 1 &amp;amp;&amp;amp; $pump_high_auto == 0){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pump_high_auto 1&amp;quot;);&lt;br /&gt;
	}elsif($pump_high_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $pump_high_auto == 1 &amp;amp;&amp;amp; $pool_kurz_auto == 1){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pool_kurz_auto 0&amp;quot;);&lt;br /&gt;
	}elsif($pump_low_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $pump_high_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $pump_high_auto == 1 &amp;amp;&amp;amp; $pool_kurz_auto == 0){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pump_high_auto 0&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
##################################&lt;br /&gt;
# Überhitzungsschutz nicht aktiv #&lt;br /&gt;
##################################&lt;br /&gt;
}else{&lt;br /&gt;
	if($heatpump_auto == 0 &amp;amp;&amp;amp; $heatpump_state eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		if($pool_kurz_state eq &amp;quot;on&amp;quot;){&lt;br /&gt;
			fhem(&amp;quot;set $ctrl_dummy pool_kurz off&amp;quot;);&lt;br /&gt;
		}	&lt;br /&gt;
		if($pool_kurz_auto == 1){&lt;br /&gt;
			fhem(&amp;quot;set $ctrl_dummy pool_kurz_auto 0&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	#################&lt;br /&gt;
	#### on-chain ###&lt;br /&gt;
	#################&lt;br /&gt;
	if($pump_low_state eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;pump_low&#039;,0) &amp;gt; $pump_high_delay &amp;amp;&amp;amp; $pump_high_auto == 0 &amp;amp;&amp;amp; $heatpump_auto == 0 &amp;amp;&amp;amp; $pool_kurz_auto == 0){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pump_high_auto 1&amp;quot;);&lt;br /&gt;
	}elsif($pump_high_state eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;pump_high&#039;,0) &amp;gt; $heatpump_delay &amp;amp;&amp;amp; $heatpump_auto == 0 &amp;amp;&amp;amp; $pool_kurz_auto == 0 &amp;amp;&amp;amp; $pump_high_auto == 1){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy heatpump_auto 1&amp;quot;);&lt;br /&gt;
	}elsif($heatpump_state eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;heatpump&#039;,0) &amp;gt; $pool_kurz_delay &amp;amp;&amp;amp; $pump_high_state eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; $pool_kurz_auto == 0 &amp;amp;&amp;amp; $pump_high_auto == 1 &amp;amp;&amp;amp; $heatpump_auto == 1){&lt;br /&gt;
		# pump_high muss on sein, da sonst die automatik ausgeschaltet wird wenn die pumpe gerade interrupted ist.&lt;br /&gt;
		# Bei unterschiedlichen Medianlängen ist es möglich, dass WP ein ist und pump_high abschaltet wegen surplus == 0&lt;br /&gt;
		# Nachbarpool würde auf EIN warten, aber pump_high dürfte nicht wieder einschalten, obwohl genügend Überschuss da ist.&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pump_high_auto 0&amp;quot;);&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pool_kurz_auto 1&amp;quot;);&lt;br /&gt;
	}elsif($pool_kurz_state eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; $pool_kurz_auto == 1 &amp;amp;&amp;amp; $heatpump_auto == 1 &amp;amp;&amp;amp; $pump_high_auto == 0){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy heatpump_auto 0&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	#################&lt;br /&gt;
	### off-chain ###&lt;br /&gt;
	#################&lt;br /&gt;
	if($pool_kurz_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;pool_kurz&#039;,0) &amp;gt; $heatpump_delay &amp;amp;&amp;amp; $pool_kurz_auto == 1 &amp;amp;&amp;amp; $heatpump_auto == 0 &amp;amp;&amp;amp; $pump_high_auto == 0){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy heatpump_auto 1&amp;quot;);&lt;br /&gt;
	}elsif($heatpump_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;heatpump&#039;,0) &amp;gt; $pump_high_delay &amp;amp;&amp;amp; $heatpump_auto == 1 &amp;amp;&amp;amp; $pump_high_auto == 0 &amp;amp;&amp;amp; $pool_kurz_auto == 1){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pool_kurz_auto 0&amp;quot;);&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pump_high_auto 1&amp;quot;);&lt;br /&gt;
	}elsif($pump_high_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $heatpump_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $pump_high_auto == 1 &amp;amp;&amp;amp; $heatpump_auto == 1 &amp;amp;&amp;amp; $pool_kurz_auto == 0){&lt;br /&gt;
#	heatpump muss aus sein, da sonst vor Ablauf der Locktime die Automatik ausgeschaltet wird und die WP nicht mehr ausschalten kann.&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy heatpump_auto 0&amp;quot;);&lt;br /&gt;
	}elsif($pump_low_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $pump_high_state eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $pump_high_auto == 1 &amp;amp;&amp;amp; $heatpump_auto == 0){&lt;br /&gt;
		fhem(&amp;quot;set $ctrl_dummy pump_high_auto 0&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
#################################################&lt;br /&gt;
# Check hardware-state vs. reading-state&lt;br /&gt;
# re-trigger notify&lt;br /&gt;
#################################################&lt;br /&gt;
my $delay_retrigger = 100; #delay time to wait until re-trigger the notify&lt;br /&gt;
&lt;br /&gt;
if(ReadingsVal($ctrl_dummy,&#039;pool_kurz&#039;,&#039;on&#039;) eq &#039;off&#039; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;pool_kurz&#039;,0) &amp;gt; $delay_retrigger &amp;amp;&amp;amp; ReadingsVal($pool_kurz_sw_kurz,&#039;state&#039;,&#039;off&#039;) eq &#039;on&#039;){&lt;br /&gt;
	# re-trigger notify&lt;br /&gt;
	fhem(&amp;quot;trigger dum_valve pool_kurz: off&amp;quot;);&lt;br /&gt;
	Log3 (&amp;quot;SolarForecast&amp;quot;, 1, &amp;quot;SolarForecast: Pool-Kurz-off must be re-triggered&amp;quot;);&lt;br /&gt;
	DebianMail(&#039;mail@example.org&#039;,&#039;Notify Pool Kurz&#039;,&amp;quot;Notify hat nicht ausgeschaltet -&amp;gt; re-trigger&amp;quot;);&lt;br /&gt;
}elsif(ReadingsVal($ctrl_dummy,&#039;pool_kurz&#039;,&#039;off&#039;) eq &#039;on&#039; &amp;amp;&amp;amp; ReadingsAge($ctrl_dummy,&#039;pool_kurz&#039;,0) &amp;gt; $delay_retrigger &amp;amp;&amp;amp; ReadingsVal($pool_kurz_sw_kurz,&#039;state&#039;,&#039;on&#039;) eq &#039;off&#039;){&lt;br /&gt;
	# re-trigger notify&lt;br /&gt;
	fhem(&amp;quot;trigger dum_valve pool_kurz: on&amp;quot;);&lt;br /&gt;
	Log3 (&amp;quot;SolarForecast&amp;quot;, 1, &amp;quot;SolarForecast: Pool-Kurz-on must be re-triggered&amp;quot;);&lt;br /&gt;
	DebianMail(&#039;mail@example.org&#039;,&#039;Notify Pool Kurz&#039;,&amp;quot;Notify hat nicht eingeschaltet -&amp;gt; re-trigger&amp;quot;);&lt;br /&gt;
}elsif((ReadingsVal($pool_kurz_sw_kurz,&#039;state&#039;,&#039;off&#039;) eq &#039;set_on&#039; || ReadingsVal($pool_kurz_sw_kurz,&#039;state&#039;,&#039;off&#039;) eq &#039;set_off&#039;) &amp;amp;&amp;amp; ReadingsAge($pool_kurz_sw_kurz,&#039;state&#039;,0) &amp;gt; $delay_retrigger){&lt;br /&gt;
	# state not clear&lt;br /&gt;
	Log3 (&amp;quot;SolarForecast&amp;quot;, 1, &amp;quot;SolarForecast: Pool-Kurz state unclear&amp;quot;);&lt;br /&gt;
	DebianMail(&#039;mail@example.org&#039;,&#039;Status Pool Kurz unklar&#039;,&amp;quot;Status HM-Schalter set_xx&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Erläuterungen:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Verzögerungen der einzelnen Stufen:&#039;&#039;&#039;&lt;br /&gt;
** Die delays der einzelnen Stufen werden aus den surpmethods berechnet. Das dient dazu, dass der Median mit den Werten nach dem ein-/ausschalten des vorheriegen Verbrauchers bis zur Hälfte + einen Wert gefüllt wird und somit sicher das Umschalten des vorherigen Verbrauchers den Median nicht mehr beeinflusst.&lt;br /&gt;
* &#039;&#039;&#039;Überhitzungsschutz:&#039;&#039;&#039;&lt;br /&gt;
** Da durch die Wärmepumpe Überschuss &amp;quot;verheizt&amp;quot; wird, der durch das Einspeiselimit gar nicht produziert würde, kann es vorkommen, dass der Pool unangenehm warm wird.&lt;br /&gt;
** Um das zu vermeiden gibt es ein Reading, welches gesetzt wird, wenn der Pool eine gewisse Temperatur überschreitet. Dieses Setzen und Zurücksetzen erfolgt mit einer Hysterese von 0.2°C, um ein Takten der Wärmepumpe zu verhindern. Diese 0.4°C sind bei dieser Wassermenge einige Stunden.&lt;br /&gt;
** Wenn der Überhitzungsschutz aktiv ist, wird die Wärmepumpe in der Kette übersprungen.&lt;br /&gt;
** Wenn sich der Hitzeschutz während des Betriebs ändert, wird die Wärmepumpe bzw. der Pool vom Nachbarn passend ausgeschaltet und die Modi entsprechend gesetzt.&lt;br /&gt;
* &#039;&#039;&#039;On-chain:&#039;&#039;&#039;&lt;br /&gt;
** Wenn am Morgen Pump Low seit $pump_low_delay aktiv ist und alle folgenden Consumer noch nicht, dann wird die nächste Stufe freigegeben. -&amp;gt; Pump High&lt;br /&gt;
** Wenn Pump High seit $pump_high_delay aktiv ist und alle folgenden Consumer noch nicht, wird die Wärmepumpe freigegeben. -&amp;gt; Heatpump&lt;br /&gt;
** Wenn die Wärmepumpe seit $heatpump_delay aktiv ist und der letzte Consumer noch nicht, wird der letzte Verbraucher freigegeben. -&amp;gt; Pool Kurz Gleichzeitig wird die Automatik für Pump High ausgeschaltet, da dieser Verbraucher erst unterbrochen werden darf wenn die Wärmepumpe aus ist!&lt;br /&gt;
** Wenn der letzte Verbraucher aktiviert ist, wird die Automatik der Wärmepumpe deaktiviert, da ja zuerst der letzte Verbraucher (Pool Kurz) wieder ausgeschaltet werden muss, bevor der vorletzte (Wärmepumpe) wieder ausgeschaltet werden darf. Da es keinen nachfolgenden Verbraucher mehr gibt, kann hier auf ein delay verzichtet werden, da es nicht passieren kann, dass zwei Verbraucher wegen sehr hohem Überschuss unmittelbar hintereinander geschaltet werden können.&lt;br /&gt;
[[Datei:Poolsteuerung mit unterschiedlichen Automatikmodi.jpg|alternativtext=Poolsteuerung|mini|Consumer der Poolsteuerung|500x500px]]&lt;br /&gt;
&#039;&#039;&#039;Wichtig:&#039;&#039;&#039; Es dürfen immer nur maximal zwei unterbrechbare Consumer im Automatikmodus sein. Der &amp;quot;aktuelle&amp;quot;, der ja aufgrund von fehlendem Überschuss jederzeit unterbrochen werden kann und der &amp;quot;folgende&amp;quot; Consumer, der auf das Einschalten wartet. Pump Low ist immer im Automatikmodus, da diese nie unterbrochen wird. (mode=must, interruptable=0)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Off-chain:&#039;&#039;&#039;&lt;br /&gt;
** Wenn der letzte Verbraucher seit mindestens der delay-Zeit aufgrund von fehlendem Überschuss inaktiv war, im Automatikmodus ist und der vorherige Verbraucher nicht im Automatikmodus ist, wird der vorherige Verbraucher in den Automatikmodus geschaltet und wartet jetzt auch auf das Ausschalten. Wenn der Überschuss steigt, springt man wieder in die on-chain und der letzte Verbraucher wird eingeschaltet und die Automatik des vorletzten Verbrauchers deaktiviert.&lt;br /&gt;
** Wenn die Wärmepumpe seit mindestens der delay-Zeit aus ist, sich im Automatikmodus befind und Pump High noch nicht im Automatikmodus ist, wird die Automatik für den Nachbarpool ausgeschaltet, da er ja jetzt nicht mehr einschalten darf, da zuerst die Wärmepumpe ein sein müsste. Die Automatik von Pump High wird wieder aktiviert, da diese jetzt auf das Ausschalten wartet. Steigt der Überschuss wieder, wird in den entsprechenden On-chain Zweig gesprungen.&lt;br /&gt;
** Wenn Pump High mindestens die delay-Zeit aus ist, wird die Automatik der Wärmepumpe deaktiviert, da diese ja erst einschalten darf, wenn Pump High wieder läuft. Steigender Überschuss führt wieder zum aktivieren von Pump High und zum Sprung in den entsprechenden On-chain Zweig.&lt;br /&gt;
** Wenn Pump Low ausgeschaltet wird, wird sofort die Automatik für Pump High ausgeschaltet, da durch das spätere Ausschalten von (der evtl. wieder eingeschalteten) Pump High, hardwaremäßig wieder Pump Low aktiviert wird, aber durch SolarForecast nie ausgeschaltet wird, da Pump Low vor ein paar Minuten ja schon logisch ausgeschaltet wurde.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wichtig:&#039;&#039;&#039; Es dürfen immer nur maximal zwei unterbrechbare Consumer im Automatikmodus sein. Der &amp;quot;aktuelle&amp;quot;, der ja aufgrund von neuem Überschuss jederzeit wieder gestartet werden kann und der &amp;quot;vorherige&amp;quot; Consumer, der auf das Ausschalten wartet.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Synchronisation Hardware vs. Reading:&#039;&#039;&#039;Manchmal passiert es, dass durch die etwas aufwendigen Umschaltprozesse die Hardware dem Reading nicht folgt/folgen kann. Evtl. Gründe sind Funkunterbrechung, verzögerte Umschaltung usw. Daher wird bei jedem Zyklus der Status geprüft und evtl. das event nochmal getriggert, um die Umschaltung erneut auszuführen.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hilfs-Notifys für die Automatik&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Da durch das Verwenden von swoffcond die Verbraucher beim Ausschalten auch ausgeplant werden, aber eigentlich &amp;quot;nur&amp;quot; unterbrochen werden sollen, müssen sie wieder neu eingeplant werden. Dazu sind notifys nötig. Wichtig: IDs müssen zweistellig angegeben werden!&lt;br /&gt;
&lt;br /&gt;
Wärmepumpe:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
dum_valve:heatpump:.off sleep 10; set energy_mgmt consumerNewPlanning 05&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Nachbar Pool:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
dum_valve:pool_kurz:.off sleep 10; set energy_mgmt consumerNewPlanning 07&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Pumpe mit einem Energiezähler als zwei Consumer verwenden&#039;&#039;&#039;  &lt;br /&gt;
&lt;br /&gt;
Die verwendete Pumpe hat vier Betriebsarten mit unterschiedlichen Leistungen. Da sie als zwei Consumer abgebildet wird, führt das dazu, dass die Leistung fälschlicherweise von SolarForecast auch zweimal gezählt wird. Die Lösung sind Dummy-Readings, welche die Leistungsdaten passend auseinander rechnen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
Pool_Strom_Pumpe:Pool_Pin31_monotonic_count_PowerCurrent:.* {&lt;br /&gt;
my $power = $EVTPART1;&lt;br /&gt;
my $pump_low = ReadingsVal(&#039;dum_valve&#039;,&#039;pump_low&#039;,&#039;off&#039;);&lt;br /&gt;
my $pump_high = ReadingsVal(&#039;dum_valve&#039;,&#039;pump_high&#039;,&#039;off&#039;);&lt;br /&gt;
my $power_low_sim = 250;&lt;br /&gt;
&lt;br /&gt;
if($pump_low eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; $pump_high eq &amp;quot;on&amp;quot;){	&lt;br /&gt;
	my $power_low = $power_low_sim; #fiktiver Verbrauch der niedrigen Stufe&lt;br /&gt;
	my $power_high = $power - $power_low_sim;&lt;br /&gt;
	fhem(&amp;quot;set dum_valve pump_low_power $power_low&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set dum_valve pump_high_power $power_high&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
elsif($pump_low eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; $pump_high eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set dum_valve pump_low_power $power&amp;quot;);&lt;br /&gt;
		fhem(&amp;quot;set dum_valve pump_high_power 0&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
elsif($pump_low eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $pump_high eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set dum_valve pump_low_power 0&amp;quot;);&lt;br /&gt;
		fhem(&amp;quot;set dum_valve pump_high_power 0&amp;quot;);&lt;br /&gt;
}elsif($pump_low eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $pump_high eq &amp;quot;on&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set dum_valve pump_low_power 0&amp;quot;);&lt;br /&gt;
		fhem(&amp;quot;set dum_valve pump_high_power $power&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Erläuterungen:&lt;br /&gt;
&lt;br /&gt;
* Es sind alle vier Möglichkeiten der zwei Pumpenlevel abgebildet.&lt;br /&gt;
* Wenn die Automatik deaktiviert ist und die Level 1-4 von extern geschaltet werden, zählen sie dadurch korrekterweise nicht zu diesen beiden Consumern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Notifys für das hardwaremäßige Schalten der Consumer&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Es werden einige Notifys verwendet, die die Umsetzung vom Dummy-Device auf die Hardware erledigen, da ein logisches Ein teilweise hardwaremäßig einige Dinge erfordert.&lt;br /&gt;
&lt;br /&gt;
Notify für Pump Low:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
dum_valve:pump_low:.* {&lt;br /&gt;
	if($EVTPART1 eq &amp;quot;on&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set Pool_Pin26 on; sleep 60; set Pool_Pin25 on; sleep 1; set Pool_Pin26 off&amp;quot;);&lt;br /&gt;
	}elsif($EVTPART1 eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set Pool_Pin14 off; sleep 5; set Pool_Pin12 off; sleep 15; set Pool_Pin25 off&amp;quot;);&lt;br /&gt;
	}else{&lt;br /&gt;
	Log3 (&amp;quot;Pool&amp;quot;, 4, qq{Notify Level1 - parameter is not on or off});&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterungen:&lt;br /&gt;
&lt;br /&gt;
* Beim Einschalten ist es nötig für eine Minute Pump High zu aktivieren, um Luft aus der Elektrolysezelle zu spülen, bevor Pump Low aktiv sein darf. (Pin26 und Pin25 sind die Steuerpins auf der Interfacekarte der Pumpe für die beiden Level.)&lt;br /&gt;
* Beim Ausschalten werden zuerst die Salzanlage (Pin14) und die pH-Anlage (Pin12) deaktiviert, damit noch 15 Sekunden lang die Elektrolysezelle mit frischem Wasser gespült wird, um das verbleibende Chlor auszuspülen.&amp;lt;br /&amp;gt;&lt;br /&gt;
Notify für Pump High:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
dum_valve:pump_high:.* {&lt;br /&gt;
	if($EVTPART1 eq &amp;quot;on&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set Pool_Pin26 on; sleep 1; set Pool_Pin25 off&amp;quot;);&lt;br /&gt;
	}elsif($EVTPART1 eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set Pool_Pin25 on; sleep 1; set Pool_Pin26 off&amp;quot;);&lt;br /&gt;
	}else{&lt;br /&gt;
	Log3 (&amp;quot;Pool&amp;quot;, 4, qq{Notify Level 2- parameter is not on or off});&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterung:&lt;br /&gt;
&lt;br /&gt;
* Da die Interfacekarte immer auf den höchsten Level reagiert, wird beim Umschalten zuerst Pump High aktiviert und nach einer Sekunde Pump Low deaktiviert, um ein &amp;quot;stufenloses&amp;quot; (ohne Ausschalten) Umschalten zu ermöglichen. Beim Ausschalten genauso.&lt;br /&gt;
&lt;br /&gt;
Notify für die Wärmepumpe:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
dum_valve:heatpump:.* {&lt;br /&gt;
	if($EVTPART1 eq &amp;quot;on&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set Pool_Pin6 on&amp;quot;);&lt;br /&gt;
	}elsif($EVTPART1 eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set Pool_Pin6 off&amp;quot;);&lt;br /&gt;
	}else{&lt;br /&gt;
	Log3 (&amp;quot;Pool&amp;quot;, 4, qq{Notify heatpump - parameter is not on or off});&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterung:&lt;br /&gt;
&lt;br /&gt;
* Hier reicht ein dirketes Übernehmen aus dem Dummy.&lt;br /&gt;
&lt;br /&gt;
Notify für den Nachbar-Pool:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
dum_valve:pool_kurz:.* {&lt;br /&gt;
	if($EVTPART1 eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; ReadingsVal(&amp;quot;Shelly_Plug_S_1&amp;quot;,&amp;quot;state&amp;quot;,&amp;quot;on&amp;quot;) eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set PwSw_Schalter off; sleep 3;{if(ReadingsAge(\&amp;quot;PwSw_Schalter\&amp;quot;,\&amp;quot;state\&amp;quot;,0)&amp;lt;4 &amp;amp;&amp;amp; ReadingsVal(\&amp;quot;PwSw_Schalter\&amp;quot;,\&amp;quot;state\&amp;quot;,\&amp;quot;on\&amp;quot;) eq \&amp;quot;off\&amp;quot;){fhem(\&amp;quot;set Shelly_Plug_S_1 on\&amp;quot;)}}; sleep 5; set PwSw_Schalter on&amp;quot;);&lt;br /&gt;
	}elsif($EVTPART1 eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; ReadingsVal(&amp;quot;Shelly_Plug_S_1&amp;quot;,&amp;quot;state&amp;quot;,&amp;quot;off&amp;quot;) eq &amp;quot;on&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set PwSw_Schalter off; sleep 3;{if(ReadingsAge(\&amp;quot;PwSw_Schalter\&amp;quot;,\&amp;quot;state\&amp;quot;,0)&amp;lt;4 &amp;amp;&amp;amp; ReadingsVal(\&amp;quot;PwSw_Schalter\&amp;quot;,\&amp;quot;state\&amp;quot;,\&amp;quot;on\&amp;quot;) eq \&amp;quot;off\&amp;quot;){fhem(\&amp;quot;set Shelly_Plug_S_1 off\&amp;quot;)}}; sleep 5; set PwSw_Schalter on&amp;quot;);&lt;br /&gt;
	}else{&lt;br /&gt;
	Log3 (&amp;quot;Pool&amp;quot;, 4, qq{Notify Pool Kurz - parameter is not on or off});&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterung&lt;br /&gt;
&lt;br /&gt;
* Da hier eine Pumpe durch einen 3-poligen Umschalter zwischen zwei Hausanspeisungen umgeschaltet wird, ist es wichtig, dass die Pumpe dazwischen &#039;&#039;&#039;gesichert&#039;&#039;&#039; zum Stehen gebracht wird! Sonst führt die rotierende Pumpe als Generator zu einem gewaltigen Kurzschluss mit der &amp;quot;fremden&amp;quot; Phase. War nicht schön ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sonderprogramme für den Poolbetrieb&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Hier ist das Aus- und Einschalten der Solarforcast-Automatik zu sehen. Es werden alle Stati gespeichert. Danach kann von beliebigen &amp;quot;Sonderfunktionen&amp;quot; (Reinigung des Filters, Massagefunktion, usw.) auf die Hardware zugegriffen werden. Wenn wieder in den Automatikmodus zurückgewechselt wird, wird hardwaremäßig wieder der Zustand der Automatik von vorher hergestellt, die Stati wieder zurück geschrieben und die Automatik wieder aktiviert.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
##############################################&lt;br /&gt;
# Status speichern und Automatik ausschalten #&lt;br /&gt;
##############################################&lt;br /&gt;
sub PoolAutoOff{&lt;br /&gt;
	my $pump_low_id			= sprintf &amp;quot;%02d&amp;quot;, 1;&lt;br /&gt;
	my $pump_high_id		= sprintf &amp;quot;%02d&amp;quot;, 3;&lt;br /&gt;
	my $heatpump_id			= sprintf &amp;quot;%02d&amp;quot;, 5;&lt;br /&gt;
	my $pool_kurz_id		= sprintf &amp;quot;%02d&amp;quot;, 7;&lt;br /&gt;
	my $sf				= &#039;energy_mgmt&#039;;&lt;br /&gt;
&lt;br /&gt;
		&lt;br /&gt;
#	my $pump_low_state = ReadingsVal($valve_dummy,&#039;pump_low&#039;,&#039;on&#039;);&lt;br /&gt;
	my $pump_low_auto	= FHEM::SolarForecast::ConsumerVal ($sf, $pump_low_id, &#039;auto&#039;, &#039;&#039;);	# Automatikmodus der Pumpe&lt;br /&gt;
#	my $pump_high_state = ReadingsVal($valve_dummy,&#039;pump_high&#039;,&#039;on&#039;);&lt;br /&gt;
	my $pump_high_auto	= FHEM::SolarForecast::ConsumerVal ($sf, $pump_high_id, &#039;auto&#039;, &#039;&#039;);	# Automatikmodus der Pumpe&lt;br /&gt;
#	my $heatpump_state = ReadingsVal($valve_dummy,&#039;heatpump&#039;,&#039;on&#039;);&lt;br /&gt;
	my $heatpump_auto	= FHEM::SolarForecast::ConsumerVal ($sf, $heatpump_id, &#039;auto&#039;, &#039;&#039;);	# Automatikmodus der Wärmepumpe&lt;br /&gt;
#	my $pool_kurz_state = ReadingsVal($valve_dummy,&#039;pool_kurz&#039;,&#039;on&#039;);&lt;br /&gt;
	my $pool_kurz_auto	= FHEM::SolarForecast::ConsumerVal ($sf, $pool_kurz_id, &#039;auto&#039;, &#039;&#039;);	# Automatikmodus des Pools&lt;br /&gt;
	fhem(&amp;quot;set $valve_dummy pump_low_auto 0&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set $valve_dummy pump_high_auto 0&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set $valve_dummy heatpump_auto 0&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set $valve_dummy pool_kurz_auto 0&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy sf_automatic 0&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_auto_pump_low $pump_low_auto&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_auto_pump_high $pump_high_auto&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_auto_heatpump $heatpump_auto&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_auto_pool_kurz $pool_kurz_auto&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	my $last_pump_level_1 = ReadingsVal($valve_dummy,&amp;quot;pump_low&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	my $last_pump_level_2 = ReadingsVal($valve_dummy,&amp;quot;pump_high&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	my $last_pump_level_3 = ReadingsVal($pump_level_3,&amp;quot;value&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	my $last_pump_level_4 = ReadingsVal($pump_level_4,&amp;quot;value&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	my $last_heatpump = ReadingsVal($valve_dummy,&amp;quot;heatpump&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_pump_level_1 $last_pump_level_1&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_pump_level_2 $last_pump_level_2&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_pump_level_3 $last_pump_level_3&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_pump_level_4 $last_pump_level_4&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_heatpump $last_heatpump&amp;quot;); &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
##########################################&lt;br /&gt;
# Status laden und Automatik einschalten #&lt;br /&gt;
##########################################&lt;br /&gt;
sub PoolAutoOn{&lt;br /&gt;
	my $last_pump_level_4 = ReadingsVal($valve_dummy,&amp;quot;last_pump_level_4&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	my $last_pump_level_3 = ReadingsVal($valve_dummy,&amp;quot;last_pump_level_3&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	my $last_pump_level_2 = ReadingsVal($valve_dummy,&amp;quot;last_pump_level_2&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	my $last_pump_level_1 = ReadingsVal($valve_dummy,&amp;quot;last_pump_level_1&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	my $last_heatpump = ReadingsVal($valve_dummy,&amp;quot;last_heatpump&amp;quot;,&amp;quot;off&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set $pump_level_4 $last_pump_level_4&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;set $pump_level_3 $last_pump_level_3&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set $pump_level_2 $last_pump_level_2&amp;quot;);&lt;br /&gt;
	if($last_pump_level_1 eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; $last_pump_level_2 eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $last_pump_level_3 eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $last_pump_level_4 eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set $pump_level_2 on; sleep 1; set $pump_level_1 $last_pump_level_1; sleep 28; set $pump_level_2 off; set $valve_dummy sf_automatic 1&amp;quot;);&lt;br /&gt;
	}elsif($last_pump_level_1 eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; $last_pump_level_2 eq &amp;quot;on&amp;quot; &amp;amp;&amp;amp; $last_pump_level_3 eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $last_pump_level_4 eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set $pump_level_1 off; set $valve_dummy sf_automatic 1&amp;quot;); &lt;br /&gt;
	}elsif($last_pump_level_1 eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $last_pump_level_2 eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $last_pump_level_3 eq &amp;quot;off&amp;quot; &amp;amp;&amp;amp; $last_pump_level_4 eq &amp;quot;off&amp;quot;){&lt;br /&gt;
		fhem(&amp;quot;set $pump_level_1 off; set $valve_dummy sf_automatic 1&amp;quot;); &lt;br /&gt;
	}&lt;br /&gt;
	fhem(&amp;quot;sleep 10; set $heatpump $last_heatpump&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_pump_level_1 none&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_pump_level_2 none&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_pump_level_3 none&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_pump_level_4 none&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_heatpump none&amp;quot;); &lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy valve_position normal&amp;quot;);&lt;br /&gt;
	my $last_auto_pump_low = ReadingsVal($valve_dummy,&amp;quot;last_auto_pump_low&amp;quot;,0);&lt;br /&gt;
	my $last_auto_pump_high = ReadingsVal($valve_dummy,&amp;quot;last_auto_pump_high&amp;quot;,0);&lt;br /&gt;
	my $last_auto_heatpump = ReadingsVal($valve_dummy,&amp;quot;last_auto_heatpump&amp;quot;,0);&lt;br /&gt;
	my $last_auto_pool_kurz = ReadingsVal($valve_dummy,&amp;quot;last_auto_pool_kurz&amp;quot;,0);&lt;br /&gt;
	fhem(&amp;quot;set $valve_dummy pump_low_auto $last_auto_pump_low&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set $valve_dummy pump_high_auto $last_auto_pump_high&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set $valve_dummy heatpump_auto $last_auto_heatpump&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set $valve_dummy pool_kurz_auto $last_auto_pool_kurz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_auto_pump_low none&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_auto_pump_high none&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_auto_heatpump none&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;setreading $valve_dummy last_auto_pool_kurz none&amp;quot;);&lt;br /&gt;
}		&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Erläuterungen:&lt;br /&gt;
&lt;br /&gt;
* pump_level_1 ist Pump Low, pump_level_2 ist Pump High, pump_level_3 und pump_level_4 sind Sonderfunktionen (Filterreinigung, Massage)&lt;br /&gt;
* Beim Wiedereinschalten von Pump Low ist es wieder nötig kurz Pump High zu aktivieren, um Luft auszuspülen.&lt;br /&gt;
* Es wird der Zustand von Solarforecast gespeichert und danach auf die Hardware geschrieben. -&amp;gt; Stellt sicher, dass nach dem Einschalten der Automatik der logical switchstate zum physical switchstate passt.&lt;br /&gt;
&lt;br /&gt;
=== Wärmepumpe (Buderus oder Bosch) per MQTT-Modul &amp;amp; BBQKees-EMS-Modul als besonderen ConsumerXX (Heatpump) für die Consumption-Prognose bei den Berechnungen in der AI::FANN einbinden ===&lt;br /&gt;
&#039;&#039;&#039;Vorhandene Hardware:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* FHEM auf einer bestehenden Hardware mit bestehendem Solarforecast&lt;br /&gt;
* Buderus WLW186-i 7 MB AR E&lt;br /&gt;
* WW-Speicher 290 ltr.&lt;br /&gt;
* Heizungspuffer 120 ltr.&lt;br /&gt;
* HK1 = FBH      -                                                         -  mit 1 x HK-Pumpe ON/OFF und 1x Mischer&lt;br /&gt;
* HK2 = (Rest-)Heizkörper im EG/1OG/Handtuchw.    -  mit 1 x HK-Pumpe ON/OFF (ohne Mischer)&lt;br /&gt;
* HK3 = Heizkörper KG (einheitlich max 16 Grad)       -  mit 1 x HK-Pumpe ON/OFF (ohne Mischer)&lt;br /&gt;
* Zusatzheizstab für Sommerbetrieb im WW-Speicher - Nutzung erfolgt nur bei PV-Überschuß tagsüber oder genügend Batterierladung am frühen Morgen gegen 04:00 Uhr.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Anforderungen / notwendige Einstellung :&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* SF ist in Betrieb und die AI::FANN sollte sich aktiv im Einsatz.&lt;br /&gt;
* Wärmepumpe befindet sich dauerhaft im temperaturgeführten Betriebsmodus.&lt;br /&gt;
* BBQKees-EMS-ESP-Modul ist angeschlossen, installiert, in Betrieb und kann per Webbrowser erreicht werden.  Beispieleinrichtung: [[Datei:Einstellung - MQTT - BBQKees.png|ohne|mini|300x300px|Einstellung - MQTT - BBQKees]]&lt;br /&gt;
* &#039;&#039;&#039;MQTT-Modul greift in FHEM auf die WP mittels BBQKees-EMS-Modul zu.&#039;&#039;&#039;   Beispiel-Device:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod MQTT_EMSwp MQTT2_DEVICE MQTT_EMSwp&lt;br /&gt;
attr MQTT_EMSwp DbLogExclude BSSID,IODev,IPv4_address,IPv4_gateway,IPv4_nameserver,IPv6_address,MAC,SSID,apicalls,\&lt;br /&gt;
apifails,attrTemplateVersion,boiler_data_auxheaterdelay,boiler_data_auxheaterlevel,\&lt;br /&gt;
boiler_data_auxheateroff,boiler_data_auxheateronly,\&lt;br /&gt;
boiler_data_auxheatersource,boiler_data_auxheatrmode,boiler_data_auxlimitstart,\&lt;br /&gt;
boiler_data_auxmaxlimit,boiler_data_burn2workmin,\&lt;br /&gt;
boiler_data_burnstarts,boiler_data_burnworkmin,boiler_data_dhw_alternatingop,boiler_data_dhw_altopprio,\&lt;br /&gt;
boiler_data_dhw_altopprioheat,boiler_data_dhw_comfdiff,boiler_data_dhw_comfort1,\&lt;br /&gt;
boiler_data_dhw_comfstop,boiler_data_dhw_disinfecting,boiler_data_dhw_disinfectiontemp,\&lt;br /&gt;
boiler_data_dhw_ecodiff,boiler_data_dhw_ecoplusdiff,\&lt;br /&gt;
boiler_data_dhw_ecoplusoff,boiler_data_dhw_ecoplusstop,boiler_data_dhw_ecostop,\&lt;br /&gt;
boiler_data_dhw_flowtempoffset,boiler_data_dhw_hystoff,boiler_data_dhw_hyston,boiler_data_dhw_maxheat,\&lt;br /&gt;
boiler_data_dhw_onetime,boiler_data_dhw_recharging,boiler_data_dhw_seltemp,\&lt;br /&gt;
boiler_data_dhw_seltemplow,boiler_data_dhw_seltempsingle,boiler_data_dhw_tempecoplus,\&lt;br /&gt;
boiler_data_dhw_workm,bootTime,boot_time,bus_status,connected,freemem,heartbeat_.*,mqttcount,mqttfails,\&lt;br /&gt;
mqttreconnects,network,rssi,rxfails,rxreceived,txfails,txreads,txwrites,uptime,uptime_sec,wifistrength,wifireconnects,\&lt;br /&gt;
thermostat_data_datetime&lt;br /&gt;
attr MQTT_EMSwp autocreate 1&lt;br /&gt;
attr MQTT_EMSwp bridgeRegexp heartbeat:.* { json2nameValue($EVENT) }&lt;br /&gt;
attr MQTT_EMSwp comment&lt;br /&gt;
Autorisierung / Token: \&lt;br /&gt;
The bearer Access Token (JWT) is used to authenticate HTTP requests and can be obtained from the \&lt;br /&gt;
WebUI&#039;s Settings-&amp;gt;Security-&amp;gt;Manage Users page and then clicking on the key icon for the user that has admin privileges (is Admin set). \&lt;br /&gt;
The token is generated using a combination of the username and a secret key which is the super user (su) password found in the WebUI&#039;s Settings-&amp;gt;Security-&amp;gt;Security Settings page. \&lt;br /&gt;
This 152 character long string must be included in the HTTP header as &amp;quot;Authorization: Bearer {ACCESS_TOKEN}&amp;quot;. Note the token has no expiry date.\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;bearer Acts Token&amp;gt; &amp;quot;dieser WLW186-7 MB AR E&amp;quot; = {ACCESS_TOKEN}\&lt;br /&gt;
Beispiele :\&lt;br /&gt;
#############\&lt;br /&gt;
# Most GETs do not need authentication\&lt;br /&gt;
% curl http://ems-esp.local/api/thermostat/seltemp\&lt;br /&gt;
\&lt;br /&gt;
# POSTs (with -d) need authentication tokens\&lt;br /&gt;
% curl http://ems-esp.local/api/thermostat/seltemp \\&lt;br /&gt;
  -H &#039;Content-Type: application/json&#039; \\&lt;br /&gt;
  -H &#039;Authorization: Bearer &amp;lt;bearer Acts Token&amp;gt;&#039; \\&lt;br /&gt;
  -d &#039;{ &amp;quot;value&amp;quot; : 22.5 }&#039;\&lt;br /&gt;
\&lt;br /&gt;
# GET with authentication using query parameter with token\&lt;br /&gt;
% curl http://ems-esp.local/api/system/publish\?access_token\=&amp;quot;ey.......0&amp;quot;\&lt;br /&gt;
\&lt;br /&gt;
# GET to restart EMS-ESP\&lt;br /&gt;
curl http://ems-esp.local/api/system/restart -H &#039;Authorization: Bearer ey....0&#039;\&lt;br /&gt;
\&lt;br /&gt;
# This example will get the system info, via a GET request\&lt;br /&gt;
curl -X GET ${emsesp_url}/api/system/info\&lt;br /&gt;
\&lt;br /&gt;
# This example will execute a read command on product ID 8 and type ID 1\&lt;br /&gt;
curl -X POST \\&lt;br /&gt;
    -H &amp;quot;Authorization: Bearer ${&amp;lt;bearer Acts Token&amp;gt;}&amp;quot; \\&lt;br /&gt;
    -H &amp;quot;Content-Type: application/json&amp;quot; \\&lt;br /&gt;
    -d &#039;{&amp;quot;data&amp;quot;:&amp;quot;8 1&amp;quot;}&#039; \\&lt;br /&gt;
    ${emsesp_url}/api/system/read\&lt;br /&gt;
\&lt;br /&gt;
# This example will export all values to a json file, including custom entities, sensors and schedules\&lt;br /&gt;
curl -X POST \\&lt;br /&gt;
    -H &amp;quot;Authorization: Bearer ${&amp;lt;bearer Acts Token&amp;gt;}&amp;quot; \\&lt;br /&gt;
    -H &amp;quot;Content-Type: application/json&amp;quot; \\&lt;br /&gt;
    -d &#039;{&amp;quot;action&amp;quot;:&amp;quot;export&amp;quot;, &amp;quot;param&amp;quot;:&amp;quot;allvalues&amp;quot;}&#039; \\&lt;br /&gt;
    ${emsesp_url}/rest/action&lt;br /&gt;
attr MQTT_EMSwp disable 0&lt;br /&gt;
attr MQTT_EMSwp event-min-interval .*:600&lt;br /&gt;
attr MQTT_EMSwp event-on-change-reading .*&lt;br /&gt;
attr MQTT_EMSwp icon air_water_heating_pump&lt;br /&gt;
attr MQTT_EMSwp model ems-esp_heater_device&lt;br /&gt;
attr MQTT_EMSwp readingList MQTT_EMSwp:ems-esp/heartbeat:.* { json2nameValue($EVENT) }\&lt;br /&gt;
MQTT_EMSwp:ems-esp/status:.* status\&lt;br /&gt;
MQTT_EMSwp:ems-esp/info:.* { json2nameValue($EVENT) }\&lt;br /&gt;
MQTT_EMSwp:ems-esp/heating_active:.* heating_active\&lt;br /&gt;
MQTT_EMSwp:ems-esp/tapwater_active:.* tapwater_active\&lt;br /&gt;
MQTT_EMSwp:ems-esp/boiler_data:.* { json2nameValue($EVENT, &#039;boiler_data_&#039;, $JSONMAP) }\&lt;br /&gt;
MQTT_EMSwp:ems-esp/thermostat_data:.* { json2nameValue($EVENT, &#039;thermostat_data_&#039;, $JSONMAP) }\&lt;br /&gt;
MQTT_EMSwp:ems-esp/mixer_data:.* { json2nameValue($EVENT, &#039;mixer_data_&#039;, $JSONMAP) }&lt;br /&gt;
attr MQTT_EMSwp room EnergieWP,MQTT2_DEVICE&lt;br /&gt;
attr MQTT_EMSwp setList restart:noArg heartbeat:.* { json2nameValue($EVENT) }&lt;br /&gt;
attr MQTT_EMSwp stateFormat T=&amp;gt;&amp;gt;   Out: boiler_data_outdoortemp ModeCirc: thermostat_data_dhw_circmode WW: boiler_data_dhw_curtemp Circ: boiler_data_dhw_circ VL: boiler_data_curflowtemp RL: boiler_data_rettemp HC1-Flow: mixer_data_hc1_flowtemphc   P.-Status HK1: mixer_data_hc1_pumpstatus P.-Status HK2: mixer_data_hc2_pumpstatus  HP_Power_Current: boiler_data_hpcurrpower   HP_Power_Reduction: boiler_data_powerreduction&lt;br /&gt;
attr MQTT_EMSwp userReadings user_WP_JAZ_overall {\&lt;br /&gt;
 if ((ReadingsNum($name,&amp;quot;boiler_data_metertotal&amp;quot;,0) &amp;gt; 0) &amp;amp;&amp;amp; (ReadingsNum($name,&amp;quot;boiler_data_nrgtotal&amp;quot;,0) &amp;gt; 0))\&lt;br /&gt;
 { \&lt;br /&gt;
(sprintf(&amp;quot;%.2f&amp;quot;, (ReadingsNum($name,&amp;quot;boiler_data_nrgtotal&amp;quot;,0)/ReadingsNum($name,&amp;quot;boiler_data_metertotal&amp;quot;,0))));;;;\&lt;br /&gt;
 }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
user_WP_JAZ_year \&lt;br /&gt;
{\&lt;br /&gt;
if ((ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPGridConsumptionYear&amp;quot;,0) &amp;gt; 0) &amp;amp;&amp;amp; (ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPboiler_data_nrgtotalYear&amp;quot;,0) &amp;gt; 0))\&lt;br /&gt;
 { \&lt;br /&gt;
(sprintf(&amp;quot;%.2f&amp;quot;, (ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPboiler_data_nrgtotalYear&amp;quot;,0)/ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPGridConsumptionYear&amp;quot;,1))));;;;\&lt;br /&gt;
 }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
user_WP_JAZ_month {\&lt;br /&gt;
if ((ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPGridConsumptionMonth&amp;quot;,0) &amp;gt; 0)&amp;amp;&amp;amp; (ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPboiler_data_nrgtotalMonth&amp;quot;,0) &amp;gt; 0))\&lt;br /&gt;
 { \&lt;br /&gt;
(sprintf(&amp;quot;%.2f&amp;quot;, (ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPboiler_data_nrgtotalMonth&amp;quot;,0)/ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPGridConsumptionMonth&amp;quot;,1))));;;;\&lt;br /&gt;
 }\&lt;br /&gt;
},\&lt;br /&gt;
\&lt;br /&gt;
user_WP_JAZ_day {\&lt;br /&gt;
 if ((ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPGridConsumptionDay&amp;quot;,0) &amp;gt; 0) &amp;amp;&amp;amp; (ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPboiler_data_nrgtotalDay&amp;quot;,0) &amp;gt; 0))\&lt;br /&gt;
 { \&lt;br /&gt;
  (sprintf(&amp;quot;%.2f&amp;quot;, (ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPboiler_data_nrgtotalDay&amp;quot;,0)/ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPGridConsumptionDay&amp;quot;,1))));;;;\&lt;br /&gt;
 }\&lt;br /&gt;
}, \&lt;br /&gt;
\&lt;br /&gt;
user_WP_JAZ_hour {\&lt;br /&gt;
 if ((ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPGridConsumptionHour&amp;quot;,0) &amp;gt; 0) &amp;amp;&amp;amp; (ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPboiler_data_nrgtotalhour&amp;quot;,0) &amp;gt; 0))\&lt;br /&gt;
 { \&lt;br /&gt;
  (sprintf(&amp;quot;%.2f&amp;quot;, (ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPboiler_data_nrgtotalhour&amp;quot;,0)/ReadingsNum(&amp;quot;Dum.Energy&amp;quot;,&amp;quot;WPGridConsumptionHour&amp;quot;,1))));;;;\&lt;br /&gt;
 }\&lt;br /&gt;
}, \&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Anmerkung: user_WP_JAZ_XXXX für Tag/Monat/Jahr werden in einem separatem Dummy (für diese Zeiträume) bei mir berechnet.  Allein user_JAZ-overall (Betrachtung der gesamten WP-Betriebszeit) wird in diesem MQTT-Device aus den hier im Device vorhanden Zahlenwerte  berechnet.&lt;br /&gt;
* &#039;&#039;&#039;Definierung des attr Heatpump-&amp;quot;consumerXX&amp;quot; in SF&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
SMA_Elgris_EM2&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt;  EM-Gesamtenergieflüsse der WP&lt;br /&gt;
type=heatpump&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; &amp;quot;Spezial&amp;quot;-Consumer - keine ON/OFF-Schaltung des Consumer durch SF bei Typ heatpump möglich !!!&lt;br /&gt;
power=2500&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; ich untertreibe hier immer etwas extra - es wird bei mir sehr wenig bis zu 3100 W verbraucht&lt;br /&gt;
icon=sani_heating_heatpump@orange&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; oder ein anderes icon nach Wahl oder des Vorhandenseins.&lt;br /&gt;
pcurr=Bezug_Wirkleistung:W&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; aus dem EM&lt;br /&gt;
etotal=Bezug_Wirkleistung_Zaehler:kWh   ## aus dem EM&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; aus dem EM&lt;br /&gt;
switchdev=MQTT_EMSwp&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; wenn man zukünftig evtl. selber schaltent eingreifen möchte&lt;br /&gt;
swstate=boiler_data_hpactivity:heating|cooling|hot.*:off&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; auf die WP-Readings zugreifen &lt;br /&gt;
comforttemp=MQTT_EMSwp:thermostat_data_hc1_comforttemp&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; Komfortemperatur des Referenzraumes (Wert für Prognose AI::FANN) meist der Wohnraum &lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; Komfortemperatur kann auch als fester Wert - z.B. 20 - eingeben werden.fest &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Anmerkung:  Kommentarzeilen bitte besser löschen falls dieser Beispiel-Code 1:1 genutzt werden soll.&lt;br /&gt;
* &#039;&#039;&#039;Definierung des attr &amp;quot;setupEnviroment&amp;quot; in SF&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
outsideTemp=MQTT_EMSwp:boiler_data_outdoortemp&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; Aussentemperatur - alternativ ein anderer T-Füher oder Wetter-App-Wert&lt;br /&gt;
presence=Forecast:user_presence:present&lt;br /&gt;
####&amp;gt;&amp;gt;&amp;gt; Anwesenheit der Bewohner mitteilen - ansonsten geht die AI::FANN in SF immer von &amp;quot;Anwesend&amp;quot; aus&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Anmerkung: &lt;br /&gt;
&lt;br /&gt;
Kommentarzeilen bitte besser löschen falls dieser Beispiel-Code 1:1 genutzt werden soll.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Definierung von notwendigen zusätzlichen &amp;quot;UserReadings&amp;quot; für &amp;quot;presence&amp;quot; in SF:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
user_presence {if(ReadingsVal(&amp;quot;Handy_01&amp;quot;,&amp;quot;state&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;present&amp;quot;) {return &amp;quot;present&amp;quot;} elsif (ReadingsVal(&amp;quot;Handy_02&amp;quot;,&amp;quot;state&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;present&amp;quot;) {return &amp;quot;present&amp;quot;} else {return 0}},&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Anmerkung: Hier wird (über die Fritzbox / PRESENCE - Device) mittels der Handys für 2 Personen die Anwesenheit festgestellt und SF bzw. der AI::FANN über das obige setupEnviroment dann (entweder - oder) als &amp;quot;true&amp;quot; mitgeteilt. Erweiterung auf 3/4/5.... möglich.&lt;br /&gt;
* Definierung der AI::FANN: Beispiel : -&amp;gt; muss nicht zutreffend sein  -&amp;gt; auch ich habe lange getestet und ändere ab und an mal die Einstellung -&amp;gt; Ergänzung bei Einsatz der AI::FANN  (nicht Ersatz für bestehende eintrage ohne AI::FANN)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ergebnis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Im folgenden Bild sieht man das Ergebnis:&lt;br /&gt;
[[Datei:Ergebnis AI-FANN Consumer-Forecast.png|ohne|mini|Ergebnis der AI-FANN Prognose]]&lt;br /&gt;
&lt;br /&gt;
== Tips &amp;amp; Tricks ==&lt;br /&gt;
* Interruptable verhält sich völlig anders, wenn der Perlcode 1 oder 0 liefert, als wenn man 1 oder 0 in der Config hinterlegt. -&amp;gt; siehe commandref&lt;br /&gt;
* Rückgabewert bei swoncond und swoffcond wird mit dem Readingswert verglichen und nicht dirket verwendet. Bsp. wenn das Reading 100 enthält muss auch der Rückgabewert des Perlcodes 100 liefern, um true zu ergeben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== weiterführende Links ==&lt;br /&gt;
* Forenthema &amp;quot;{{Link2Forum|Topic=137058|LinkText=76_SolarForecast - Informationen/Ideen zu Weiterentwicklung und Support}}&amp;quot;&lt;br /&gt;
* Solcast API Toolkit: https://toolkit.solcast.com.au&lt;br /&gt;
* Kostal Plenticore 10 Plus mit SQL-Datenbank Integration ([[Kostal Plenticore 10 Plus]])&lt;br /&gt;
* Photovoltaik Ingenieurbüro Junge: https://www.ing-büro-junge.de/html/photovoltaik.html&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=SetList&amp;diff=40497</id>
		<title>SetList</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=SetList&amp;diff=40497"/>
		<updated>2025-11-21T13:43:29Z</updated>

		<summary type="html">&lt;p&gt;Maista: Es waren falscher Devicenamen im userReadings (oil) angegeben&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:setList}}  &amp;lt;!-- da richtige Schreibweise kleinen Anfangsbuchstaben hat --&amp;gt;&lt;br /&gt;
&amp;lt;!-- Infobox Attribut sinnvoll? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Attribut [[setList]] dient dazu, bei generischen Devices die Liste der möglichen set Kommandos zu spezifizieren. &lt;br /&gt;
&lt;br /&gt;
{{Todo|Bitte analog zu [[eventMap]] mit Inhalt füllen.}}&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
Das &#039;&#039;setList&#039;&#039; Attribut wird in der folgenden Weise spezifiziert:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;attr &amp;lt;device&amp;gt; setList &amp;lt;Reading1&amp;gt;:⟨&amp;lt;Modifier1&amp;gt;,⟩&amp;lt;Value1&amp;gt;,&amp;lt;Value2&amp;gt;,&amp;lt;...&amp;gt; &amp;lt;Reading2&amp;gt;:⟨&amp;lt;Modifier2&amp;gt;,⟩&amp;lt;Value1&amp;gt;,&amp;lt;Value2&amp;gt;,&amp;lt;...&amp;gt; ...&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
Es ist auch möglich, zur Verbesserung der Übersichtlichkeit und Lesbarkeit, das setList Attribut mehrzeilig zu formulieren.&lt;br /&gt;
&lt;br /&gt;
== Einschränkungen == &lt;br /&gt;
Dieses Attribut existiert nur bei [[DOIF]]-, [[dummy]]-, [[MSwitch]]- und [[readingsProxy]]-Devices.&lt;br /&gt;
[[MQTT2 DEVICE]] nutzt setList um Änderungen an State bzw. Readings an den Server zu übermitteln, der diese dann an die eigentlichen Geräte weitergibt oder dort vorhält. Für jedes Reading ist eine eigene Zeile erforderlich, das Aussehen in der Detailansicht des Geräts kann direkt über eine entsprechende widget-Definition vorgenommen werden.&lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
&lt;br /&gt;
In diesem ersten Beispiel wird der &#039;&#039;state&#039;&#039; als Schiebebalken (slider) angezeigt. Wobei die erste Zahl den niedrigsten möglichen Wert angibt. Die zweite den Wert, um den jeweils erhöht wird. Und die dritte den maximal möglichen Wert.&lt;br /&gt;
 define Raumtemperatur dummy&lt;br /&gt;
 attr Raumtemperatur setList :slider,10,0.5,30&lt;br /&gt;
&lt;br /&gt;
Wenn beim Einstellen per Slider auch Fließkommazahlen angezeigt werden sollen, kann man den optionalen Parameter &#039;&#039;isFloat&#039;&#039; auf 1 setzen. In diesem Beispiel wird die Kalibrierung der Temperaturanzeige eines Bodenfeuchtigkeitssensors zwischen -2° und +2° in 0,1°-Schritten definiert und soll auch in 0,1°-Schritten angezeigt werden. Hierzu dient das abschließende &#039;&#039;,1&#039;&#039;:&lt;br /&gt;
 attr Feuchtigkeitssensor setList :slider,-2,0.1,2,1&lt;br /&gt;
&lt;br /&gt;
Hier wird für den &#039;&#039;state&#039;&#039; eine Uhrzeit angegeben. Die kann mit zwei Schiebebalken (einer für die Stunden, einer für die Minuten) gesetzt werden.&lt;br /&gt;
 define Wecker_Uhrzeit dummy&lt;br /&gt;
 attr Wecker_Uhrzeit setList :time&lt;br /&gt;
&lt;br /&gt;
Möchte man Farbwerte einstellen, kann man &#039;&#039;colorpicker&#039;&#039; verwenden. Damit kann dann auf einer Palette eine Farbe gewählt werden.&lt;br /&gt;
 define Farbe dummy&lt;br /&gt;
 attr Farbe setList :colorpicker&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 define Wecker_Uhrzeit dummy&lt;br /&gt;
 attr Wecker_Uhrzeit setList state:AUS,05:00,05:15,05:30,05:45,06:00,06:15,06:30,06:35,06:40,06:45,06:50,06:55,07:00,07:05,07:10,07:15,07:20,07:25,07:30,07:45,08:00,08:15,08:30,08:45,09:00,09:15,09:30,09:45,10:00,10:15,10:30,10:45,11:00,11:15,11:30,11:45,12:00,12:15,12:30,12:45,13:00,13:15,13:30,13:45,14:00,14:15,14:30,14:45,15:00,15:15,15:30,15:45,16:00,16:15,16:30,16:45,17:00,17:15,17:30,17:45,18:00,18:15,18:30,18:45,19:00,19:15,19:30,19:45,20:00,20:15,20:30,20:45,21:00,21:15,21:30,21:45,22:00,22:15,22:30,22:45,23:00,23:15,23:30,23:45,00:00,00:15,00:30,00:45,01:00,01:15,01:30,01:45,02:00,02:15,02:30,02:45,03:00,03:15,03:30,03:45,04:00,04:15,04:30,04:45&lt;br /&gt;
 attr Wecker_Uhrzeit readingList state&lt;br /&gt;
 attr Wecker_Uhrzeit webCmd state&lt;br /&gt;
&lt;br /&gt;
 define Beschattung_auto dummy&lt;br /&gt;
 attr Beschattung_auto setList state:aktiv,passiv&lt;br /&gt;
 attr Beschattung_auto readingList state&lt;br /&gt;
 attr Beschattung_auto webCmd state&lt;br /&gt;
&lt;br /&gt;
 define Heizungsmodus dummy&lt;br /&gt;
 attr Heizungsmodus setList state:auto,FHEM,Frostschutz,AUS&lt;br /&gt;
 attr Heizungsmodus readingList state&lt;br /&gt;
 attr Heizungsmodus webCmd state&lt;br /&gt;
&lt;br /&gt;
 define TV_ProgrammKanal dummy&lt;br /&gt;
 attr TV_ProgrammKanal setList ARD_Ch ZDF_Ch HR_Ch RTL_Ch Sat1_Ch VOX_Ch Pro7_Ch Kabel1_Ch COMEDYCENTRAL_Ch DREISAT_Ch ARTE_Ch EINSPLUS_Ch EINSFESTIVAL_Ch ZDFNEO_Ch NDR_Ch MDR_Ch BR_Ch RBB_Ch SWR_Ch WDR_Ch RTL2_Ch SUPERRTL_Ch SPORT1_Ch EUROSPORT_Ch DMAX_Ch N24_Ch NTV_Ch RTLNITRO_Ch SAT1GOLD_Ch SIXX_Ch TELE5_Ch&lt;br /&gt;
 attr TV_ProgrammKanal readingList state&lt;br /&gt;
&lt;br /&gt;
 define benzinpreis dummy&lt;br /&gt;
 attr benzinpreis readingList SuperE5_2 SuperPlus_2&lt;br /&gt;
 attr benzinpreis setList SuperE5_2:slider,140,1,200 SuperPlus_2:slider,140,1,200&lt;br /&gt;
 attr benzinpreis stateFormat SuperE5, SuperPlus&lt;br /&gt;
 attr benzinpreis userReadings SuperE5 {(ReadingsVal(&amp;quot;benzinpreis&amp;quot;,&amp;quot;SuperE5_2&amp;quot;,0) / 100 )}, SuperPlus {(ReadingsVal(&amp;quot;benzinpreis&amp;quot;,&amp;quot;SuperPlus_2&amp;quot;,0) / 100 )}&lt;br /&gt;
 attr benzinpreis webCmd SuperE5_2:SuperPlus_2&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Ausführliche Beschreibung (mit Beispielen) zu [[eventMap]], [[devStateIcon]], setList und [[webCmd]] in {{Link2Forum|Topic=12080|LinkText=diesem Forenthread}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Attribut (allgemeingültig)]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=DOIF/uiTable_Schnelleinstieg&amp;diff=37247</id>
		<title>DOIF/uiTable Schnelleinstieg</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=DOIF/uiTable_Schnelleinstieg&amp;diff=37247"/>
		<updated>2022-02-19T22:36:23Z</updated>

		<summary type="html">&lt;p&gt;Maista: An der Klammer lang es nicht ?!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Datei:UiTable state screen.png|700px|rechts|Webansicht bestehend aus mehreren DOIF/uiTable-Definitionen]]&lt;br /&gt;
An dieser Stelle wird das DOIF-Web-Interface erklärt, welches über das DOIF-Attribut &#039;&#039;&#039;uiTable&#039;&#039;&#039; realisiert wurde. &lt;br /&gt;
&lt;br /&gt;
Abhängig von der Art der Funktion können in einer tabellarischen Darstellung FHEM-Geräte visualisiert und über die Web-Oberfläche bedient werden. Eventbasierte Änderungen visualisierter Readings werden unmittelbar in der Web-Ansicht aktualisiert. Eine erstellte Tabelle erscheint unterhalb der Statuszeile eines DOIF-Devices. Das uiTable-Attribut kann in bereits bestehenden DOIFs oder in funktionslosen DOIFs, wie in den unteren Beispielen, als reines WEB-Interface erstellt werden. In der Abbildung rechts ist ein Statusbildschirm aus vier Spalten mit mehreren DOIF/uiTable-Definitionen aufgebaut worden.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Darstellungsmöglichkeiten werden anhand von Beispielen insb. mit Hilfe bereits im DOIF-Modul vordefinierter uiTable-Funktionen aufgezeigt. Diese Perlfunktionen sind in einem eigenen Package namens &#039;ui_Table&#039; definiert worden. Mit Hilfe dieser Funktionen lassen sich recht einfach, ohne tiefere HTML/CSS-Kenntnisse, eigene Übersichten definieren. Im Anschluss werden typische &#039;&#039;&#039;[[DOIF/uiTable Schnelleinstieg#Anwendungsbeispiele|Anwendungsbeispiele]]&#039;&#039;&#039; aufgezeigt.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Beispieldefinitionen arbeiten mit konkreten Geräten und Readings, sie können als RAW-Definition ins eigene System übernommen werden, dazu müssen die Gerätenamen, Readings, ggf. auch Icons den existierenden Namen des eigenen Systems angepasst werden. Zum Ausprobieren der Beispiele können statt echter Geräte auch Dummys benutzt werden. &lt;br /&gt;
&lt;br /&gt;
Es gibt im Perl-Modus des DOIF-Moduls ebenfalls das Attribut &#039;&#039;&#039;uiState&#039;&#039;&#039;, welches die gleiche Syntax wie uiTable nutzt. Die definierte Tabelle erscheint im Gegensatz zu uiTable jedoch im Status des DOIF-Devices. uiState und uiTable können gleichzeitig in einem DOIF-Device definiert werden.  &lt;br /&gt;
&lt;br /&gt;
== Aufbau des uiTable-Attributs ==&lt;br /&gt;
Im uiTable-Attribut wird in erster Linie die zu visualisierende Tabelle definiert. Optional können zuvor ein Perlblock sowie Templates definiert werden.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;Aufbau des Attributs&#039;&#039;&#039;&lt;br /&gt;
* das uiTable-Attribut besteht aus drei Bereichen:&lt;br /&gt;
* [[DOIF/uiTable Schnelleinstieg#Der Perlblock|Perlblock]]&lt;br /&gt;
* [[DOIF/uiTable Schnelleinstieg#uiTable-Templates|Templates-Definitionen]] &lt;br /&gt;
* [[DOIF/uiTable Schnelleinstieg#Die Tabellendefinition|Tabellendefinition]]&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;Aufbaustruktur&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
&amp;lt;Perlblock, optional&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;Templates-Definitionen, optional&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;Tabellendefinition&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Der Perlblock ===&lt;br /&gt;
Der Perlblock dient dazu, das Layout der Tabelle zu beeinflussen sowie eigene uiTable-Funktionen zu definieren. Hier wird insb. das Package definiert, welches für die Tabellendefinition gilt. Ebenfalls können CSS-Variablen sowie Steuerungsattribute gesetzt werden. Der Perlblock beginnt und endet mit einer geschweiften Klammer.&lt;br /&gt;
&lt;br /&gt;
==== CSS-Variablen und Steuerungsattribute ====&lt;br /&gt;
Mit Hilfe von CSS-Variablen kann das Layout der Tabelle beeinflusst werden. Die Steuerungsattribute beeinflussen die Statuszeile sowie die Detailansicht des DOIF-Moduls.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;CSS-Variablen und Steuerungsattribute&#039;&#039;&#039;&lt;br /&gt;
*Das Layout der gesamten Tabelle wird beeinflusst über die Variablendefinition: &#039;&#039;&#039;$TABLE=&amp;quot;&amp;lt;CSS-Attribute der Tabelle&amp;gt;&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
*Spaltenformatierungen werden beeinflusst mit Hilfe der Variablendefinition: &#039;&#039;&#039;$TC{&amp;lt;Zellenbereich für Spalten&amp;gt;}=&amp;quot;&amp;lt;CSS-Attribute der Spalten&amp;gt;&amp;quot;&#039;&#039;&#039; &lt;br /&gt;
*Zeilenformatierungen werden beeinflusst mit Hilfe der Variablendefinition: &#039;&#039;&#039;$TR{Zeilenbereich}=&amp;quot;&amp;lt;CSS-Attribute der Zeilen&amp;gt;&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
*einzelne Zellen werden beeinflusst mit Hilfe der Variablen: &#039;&#039;&#039;$TD{&amp;lt;Zellenbereich für Zeilen&amp;gt;}{&amp;lt;Zellenbereich für Spalten&amp;gt;}=&amp;quot;&amp;lt;CSS-Attribute der Zellen&amp;gt;&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
*für Zellen-, Spalten- und Zeilen-Bereich gilt: &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;&amp;lt;kommagetrennte Aufzählung&amp;gt;&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;&amp;lt;Bereich von..bis&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
*Der Status in der Statuszeile des DOIFs wird ausgeblendet mit &#039;&#039;&#039;$SHOWNOSTATE=1&#039;&#039;&#039;&lt;br /&gt;
*Die Gerätezeile des DOIFs wird ausgeblendet mit &#039;&#039;&#039;$SHOWNODEVICELINE = &amp;quot;&amp;lt;regex room&amp;gt;&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
*Die Tabelle des DOIFs wird ausgeblendet mit &#039;&#039;&#039;$SHOWNOUITABLE = &amp;quot;&amp;lt;regex room&amp;gt;&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
*Die Detailansicht wird umorganisiert mit &#039;&#039;&#039;$ATTRIBUTESFIRST=1&#039;&#039;&#039;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;Bespieldefinition&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_bsp_layout DOIF ##&lt;br /&gt;
attr di_bsp_layout uiTable { ## Beginn des Perlblocks\&lt;br /&gt;
## CSS-Variablen\&lt;br /&gt;
\&lt;br /&gt;
## Die Tabelle soll ein Hintergrundbild der Größe 300x300 Pixel haben\&lt;br /&gt;
$TABLE = &amp;quot;width:300px;; height:300px;; background-image:url(/fhem/www/pgm2/images/Grundriss.png);; background-size: 300px 300px;;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
## die Zelle der ersten Zeile und der ersten Spalte soll rechts eine Rahmenlinie haben\&lt;br /&gt;
$TD{0}{0} = &amp;quot;style=&#039;border-right-style:solid;; border-right-width:10px&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
## Die erste Zeile soll aus der Klasse &#039;odd&#039; sein und fett-Schrift haben\&lt;br /&gt;
$TR{0} = &amp;quot;class=&#039;odd&#039; style=&#039;font-weight:bold&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
## die Spalten 2 bis 6 sollen zentriert sein\&lt;br /&gt;
$TC{1..5} = &amp;quot;align=&#039;center&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
## die Spalten 2, 4 und 5 sollen zentriert sein\&lt;br /&gt;
$TC{1,3,5} = &amp;quot;align=&#039;center&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
## die letzte Spalte der Tabelle soll fett sein\&lt;br /&gt;
$TC{last} = &amp;quot;style=&#039;font-weight:bold&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
\## Steuerungsattribute\&lt;br /&gt;
\&lt;br /&gt;
\## Ausblenden des Status in der Statuszeile\&lt;br /&gt;
$SHOWNOSTATE=1;;\&lt;br /&gt;
\&lt;br /&gt;
## Die Gerätezeile wird ausgeblendet in allen Räumen\&lt;br /&gt;
$SHOWNODEVICELINE = &amp;quot;.*&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
## Die Tabelle wird im Raum info ausgeblendet\&lt;br /&gt;
$SHOWNOUITABLE = &amp;quot;^info$&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
## Die Detailansicht wird umorganisiert, hilfreich beim Editieren längerer uiTable-Definitionen\&lt;br /&gt;
$ATTRIBUTESFIRST = 1;;\&lt;br /&gt;
} ## Ende des Perlblocks&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Die Tabellendefinition ===&lt;br /&gt;
==== Einfache Tabellendefinition ohne Funktionen ====&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;Tabellendefinition&#039;&#039;&#039;&lt;br /&gt;
* eine Tabelle wird aus Zellen zusammengebaut&lt;br /&gt;
* mehrere Zellen werden mit &amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; von einander getrennt, sie bilden eine Tabellenzeile&lt;br /&gt;
* eine neue Tabellenzeile beginnt mit einer neuen Zeile in der Tabellendefinition&lt;br /&gt;
* eine Tabellenzeile kann auch in mehreren Zeilen definiert werden, diese müssen dann mit &amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; enden&lt;br /&gt;
* Texte werden in Anführungszeichen angegeben&lt;br /&gt;
* Readings werden in der Form [&amp;lt;device&amp;gt;:&amp;lt;reading&amp;gt;] angegeben&lt;br /&gt;
* Kommentare beginnen mit ## und enden mit Zeilenende&lt;br /&gt;
* Events eines definierten Readings, führen sofort zu Aktualisierung seines Inhalts in der visualisierten Tabelle&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod ui_Table_definition DOIF ##&lt;br /&gt;
attr ui_Table_definition uiTable { ## Perlblock für globale Tabellendefinitionen\&lt;br /&gt;
 \&lt;br /&gt;
 $TC{1..2}=&amp;quot;align=&#039;center&#039;&amp;quot; ## zentrierte Ausrichtung der zweiten und dritten Spalte\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Warmwasser&amp;quot;|&amp;quot;Vorlauf&amp;quot;|&amp;quot;Rücklauf&amp;quot;   ## erste Tabellenzeile\&lt;br /&gt;
									## zweite Tabellenzeile\&lt;br /&gt;
[T_Warmwasserspeicher:temperature]| ## Zeile wird fortgesetzt, da sie mit | endet\&lt;br /&gt;
[T_Vorlauf:temperature]|            ## Zeile wird fortgesetzt, da sie mit | endet\&lt;br /&gt;
[T_Ruecklauf:temperature]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable Definition.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
==== Tabellendefinition mit Berechnungen ====&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;Zellenauswertung&#039;&#039;&#039;&lt;br /&gt;
* jede Zelle der Tabelle wird über Perl ausgewertet&lt;br /&gt;
* Readingangaben der Form [&amp;lt;device&amp;gt;:&amp;lt;reading&amp;gt;] werden in eine Perlfunktion übersetzt&lt;br /&gt;
* das Ergebnis des ausgewerteten Perlausdrucks wird ausgegeben&lt;br /&gt;
* in einer Zelle können beliebige Perlfunktionen genutzt werden&lt;br /&gt;
* Texte oder Funktionen können mit Punkt aneinander gehängt werden&lt;br /&gt;
* mit Komma werden Texte oder Werte untereinander dargestellt&lt;br /&gt;
* wird eine Zeile mit &amp;lt; abgeschlossen, so wird die aktuelle Tabelle abgeschlossen, die nächste Zeile beginnt in einer neuen Tabelle&lt;br /&gt;
* in einer Berechnung sollte ein Trigger in Form einer Readingangabe [&amp;lt;device&amp;gt;:&amp;lt;reading&amp;gt;] vorkommen, sonst wäre das Ergebnis statisch und würde sich nicht ändern &lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_calc DOIF ##&lt;br /&gt;
attr di_uiTable_calc uiTable ## Tabellendefinition\&lt;br /&gt;
&amp;quot;Differenz&amp;quot;|[T_Ruecklauf:temperature]-[T_Vorlauf:temperature]\&lt;br /&gt;
&amp;quot;Minimum&amp;quot;|minNum([TH_WZ_HM:measured-temp],[TH_Keller_HM:measured-temp])\&lt;br /&gt;
&amp;quot;Durchschnitt&amp;quot;|([T_Ruecklauf:temperature]+[T_Vorlauf:temperature])/2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable calc.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
== Vordefinierte uiTable-Funktionen ==&lt;br /&gt;
Typische Widgets bzw. Styles wurden als Perl-Funktionen im package ui_Table für eine einfache Tabellendefinition programmiert. Im folgenden wird näher auf die einzelnen uiTable-Funktionen eingegangen.&lt;br /&gt;
&lt;br /&gt;
=== FHEM-Widgets mit der Funktion &#039;&#039;&#039;widget&#039;&#039;&#039; ===&lt;br /&gt;
Alle in FHEM vorhanden Widgets können mit Hilfe der Perlfunktion &#039;&#039;&#039;widget&#039;&#039;&#039; genutzt werden. Bei häufiger Nutzung eines bestimmten Widgets bietet sich alternativ die Definition einer uiTable-Funktion (Typ 3) mit dem jeweiligen Widget an, siehe: [[DOIF/uiTable Schnelleinstieg#Eigene uiTable-Funktionen programmieren|uiTable-Funktion]]&lt;br /&gt;
{{Randnotiz|RNText=Funktion &#039;&#039;&#039;widget&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
widget(&amp;lt;Reading&amp;gt;,$fhem_widget,$set)&lt;br /&gt;
&lt;br /&gt;
Reading      # [&amp;lt;device&amp;gt;:&amp;lt;reading&amp;gt;]&lt;br /&gt;
$fhem_widget # Angabe des FHEM-Widgets&lt;br /&gt;
$set         # optional, undef zum Setzen beliebiger Readings (entspricht setreading), &amp;quot;set&amp;quot; wenn das Reading per set-Befehl gesetzt wird (siehe Attribut ReadingList), &amp;quot;set &amp;lt;Befehl&amp;gt;&amp;quot;, wenn sich der Befehl vom Reading unterscheidet, default undef&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* [[FHEMWEB/Widgets|Fhem-Widgets]]&lt;br /&gt;
* Fhem-Widgets als [[DOIF/uiTable Schnelleinstieg#Eigene uiTable-Funktionen programmieren|uiTable-Funktion]]&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_widget DOIF ##&lt;br /&gt;
attr di_uiTable_widget uiTable ## FHEM-Widgets mit Hilfe der WID-Funktion\&lt;br /&gt;
{package ui_Table}\&lt;br /&gt;
&amp;quot;Widget&amp;quot;\&lt;br /&gt;
&amp;quot;Select&amp;quot;| widget([uhr:wochentag],&amp;quot;select,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag,Sonntag&amp;quot;)\&lt;br /&gt;
&amp;quot;Selectnumbers&amp;quot;| widget([motor:spannung],&amp;quot;selectnumbers,0,0.5,12,1,lin&amp;quot;)\&lt;br /&gt;
&amp;quot;Slider&amp;quot;| widget([bla:wert],&amp;quot;slider,0,5,100,1&amp;quot;)\&lt;br /&gt;
&amp;quot;Colorpicker RGB&amp;quot;| widget([Lampe:farbe],&amp;quot;colorpicker,RGB&amp;quot;)\&lt;br /&gt;
&amp;quot;Colorpicker HSV&amp;quot;| widget([Lampe:farbe],&amp;quot;colorpicker,HSV&amp;quot;)\&lt;br /&gt;
&amp;quot;Colorpicker CT&amp;quot;| widget([Lampe:waerme],&amp;quot;colorpicker,CT,2000,10,6500&amp;quot;)\&lt;br /&gt;
&amp;quot;Colorpicker HUE&amp;quot;| widget([Lampe:farbe],&amp;quot;colorpicker,HUE,0,1,359&amp;quot;)\&lt;br /&gt;
&amp;quot;Colorpicker BRI&amp;quot;| widget([Lampe:helligkeit],&amp;quot;colorpicker,BRI,0,1,100&amp;quot;)\&lt;br /&gt;
&amp;quot;Time&amp;quot;| widget([start:zeit],&amp;quot;time&amp;quot;)\&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable WID.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
=== SVG-uiTable-Funktionen ===&lt;br /&gt;
SVG-uiTable-Funktionen sind skalierbare Widgets, die auf SVG-Elementen basieren. Bei allen SVG-Funktionen für Temperatur bzw. Feuchtigkeit wird die Einfärbung abhängig vom Temperatur- bzw. Feuchtigkeitswert mit Hilfe einer Zuordnungsfunktion bestimmt.&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;ring&#039;&#039;&#039;-Funktionen ====&lt;br /&gt;
===== Farbskalierte Temperaturanzeige mit Hilfe der SVG-Funktionen &#039;&#039;&#039;temp_ring/temp_mring&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe der dargestellten Temperatur ist abhängig vom Temperaturwert. Die Helligkeit der Farbgebung ist einstellbar. Bei der &#039;&#039;&#039;temp_mring&#039;&#039;&#039;-SVG-Funktion wird der Ring einfarbig dargestellt.&lt;br /&gt;
&lt;br /&gt;
Farbskalierung der &#039;&#039;&#039;temp_ring&#039;&#039;&#039;-SVG-Funktion:&lt;br /&gt;
[[Datei:Farbskalierung temp_ring_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
Farbskalierung der &#039;&#039;&#039;temp_mring&#039;&#039;&#039;-SVG-Funktion:&lt;br /&gt;
[[Datei:Farbskalierung temp_mring_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;temp_ring/temp_mring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
temp_ring/temp_mring ($temp_value,$temp_min,$temp_max,$sizeHalf, $lightring,$lightnumber,$decFont) &lt;br /&gt;
&lt;br /&gt;
$temp_value  # Temperatur&lt;br /&gt;
$temp_min,   # minimale Temperatur, optional, default=-20&lt;br /&gt;
$temp_max,   # maximale Temperatur, optional, default=60&lt;br /&gt;
$sizeHalf    # &amp;quot;&amp;lt;size&amp;gt;,&amp;lt;half ring&amp;gt;&amp;quot; size: Größe der Grafik, optional, default = 80, half ring: 1 für Halbring&lt;br /&gt;
$lightring,  # Helligkeit des Ringes (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFont     # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_temp_ring DOIF ##&lt;br /&gt;
attr di_temp_ring uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;außen (standard)&amp;quot;|temp_ring([Aussensensor:temperature])\&lt;br /&gt;
&amp;quot;Warmwasser (größer,aufgehellt,Normalschrift)&amp;quot; |temp_mring([vaillant:WWSpeicher],15,70,110,90,100,&amp;quot;1,font-weight:normal&amp;quot;)\&lt;br /&gt;
&amp;quot;Vorlauf (größer)&amp;quot;| temp_mring([ESPEasy_ESP_Temp_Vorlauf:Temperature],15,45,100)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:temp_ring_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Feuchtigkeitsanzeige mit Hilfe der SVG-Funktionen &#039;&#039;&#039;hum_ring/hum_mring&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe der dargestellten Feuchtigkeit ist abhängig vom Feuchtigkeitswert. Die Helligkeit der Farbgebung ist einstellbar. Bei der &#039;&#039;&#039;hum_mring&#039;&#039;&#039;-SVG-Funktion wird der Ring einfarbig dargestellt.&lt;br /&gt;
&lt;br /&gt;
Farbskalierung der &#039;&#039;&#039;hum_ring&#039;&#039;&#039;-SVG-Funktion: &lt;br /&gt;
[[Datei:Farbskalierung hum_ring_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
Farbskalierung der &#039;&#039;&#039;hum_mring&#039;&#039;&#039;-SVG-Funktion:&lt;br /&gt;
[[Datei:Farbskalierung hum_mring_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;hum_ring/hum_mring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
hum_ring/hum_mring ($hum_value,$sizeHalf,$lightring,$lightnumber,$decFont) &lt;br /&gt;
$hum_value   # Feuchtigkeit&lt;br /&gt;
$sizeHalf  # &amp;quot;&amp;lt;size&amp;gt;,&amp;lt;half ring&amp;gt;&amp;quot; size: Größe der Grafik, optional, default = 80, half ring: 1 für Halbring&lt;br /&gt;
$lightring   # Helligkeit des Ringes (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFont     # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_hum_ring DOIF ##&lt;br /&gt;
attr di_hum_ring room test2&lt;br /&gt;
attr di_hum_ring uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;klein ohne Farbverlauf&amp;quot;|hum_mring([Aussensensor:humidity],60)\&lt;br /&gt;
&amp;quot;normal groß mit Farbverlauf&amp;quot;|hum_ring([Aussensensor:humidity])\&lt;br /&gt;
&amp;quot;groß ohne Farbverlauf aufgehellt&amp;quot;|hum_mring([Aussensensor:humidity],100,80)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:hum_ring_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige eines Zahlenwertes mit Hilfe der universellen SVG-Funktion &#039;&#039;&#039;ring&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe des dargestellten Wertes kann abhängig vom Wert bestimmt werden. Dabei wird die Farbe mit Anleihen aus dem [https://de.wikipedia.org/wiki/HSV-Farbraum HSV-Farbraum] bestimmt. Dieser Farbraum benötigt eigentlich drei Werte, wobei die erste den Farbton (hue) bestimmt; hier wird nur dieser Wert verwendet (Sättigung und Hellwert sind nicht einstellbar). Der Farbton geht von rot (hue-Wert = 0) über gelb (hue-Wert = 60), dann grün (hue-Wert = 120) und blau (hue-Wert = 240) zurück zu rot (hue-Wert = 360), siehe dazu auch die [https://de.wikipedia.org/wiki/HSV-Farbraum#/media/Datei:HueScale.svg Farbtontafel] auf der Wikipedia-Seite.&lt;br /&gt;
Die unten $colorRef genannte Funktion kann zum Beispiel in der Tabelle selbst definiert werden, beispielsweise kann man in dem device &amp;amp;onoff_hue verwenden, wenn man es vorab definiert (siehe [https://forum.fhem.de/index.php/topic,120088.msg1204341.html#msg1204341 Link zum Forum]):&amp;lt;blockquote&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
attr &amp;lt;ui device Name&amp;gt; {&lt;br /&gt;
  package ui_Table;&lt;br /&gt;
    sub onoff_hue {&lt;br /&gt;
    my($irgendeinVariablenname)=@_;&lt;br /&gt;
    return ($irgendeinVariablenname == 0 ? 240 : 0); &lt;br /&gt;
  }&lt;br /&gt;
## Tabellendefinition&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;/blockquote&amp;gt;{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;ring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
ring ($value,$min,$max,$minColor,$maxColor,$unit, $sizeHalf,$colorRef,$decFont,$model,$lightness)&lt;br /&gt;
&lt;br /&gt;
$value     # darzustellender Wert&lt;br /&gt;
$min       # minimaler Wert, optional, default=0&lt;br /&gt;
$max       # maximaler Wert, optional, default=100&lt;br /&gt;
$minColor  # Farbe (hue: 0-360) des kleinsten Wertes, optional, default = undef&lt;br /&gt;
$maxColor  # Farbe (hue: 0-360) des maximalen Wertes, optional, default = undef&lt;br /&gt;
$unit      # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$sizeHalf  # &amp;quot;&amp;lt;size&amp;gt;,&amp;lt;half ring&amp;gt;&amp;quot; size: Größe der Grafik, optional, default = 100, half ring: 1 für Halbring&lt;br /&gt;
$colorRef  # Referenz auf eine Funktion, die zu einem Wert einen Farbwert (hue: 0-360) bestimmt, oder eine Referenz auf eine Arrayliste mit Grenzwerten und Farben, optional, default = undef&lt;br /&gt;
$decFont   # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$model      # &#039;&amp;lt;Farbverlauf&amp;gt;,&amp;lt;Min/Max&amp;gt;,&amp;lt;Innenring&amp;gt;,&amp;lt;Zeigerstärke&amp;gt;,&amp;lt;Modus&amp;gt;&#039;,&lt;br /&gt;
            #   Farbverlauf: 1 für monochrom, &lt;br /&gt;
            #   Min/Max: Style-SVG-Attribute oder 1 zum Anzeigen der Min-/Maxwerte,&lt;br /&gt;
            #   Innenring: Style-SVG-Attribute oder 1 zum Anzeigen des Innenringes, Zeigerstärke: in Pixel,&lt;br /&gt;
            #   Zeigerstärke: Breite des Zeigers,&lt;br /&gt;
            #   Modus: 0 Standard Min-Max, 1 Min-Null-Max, 2 Null-Min/Max,&lt;br /&gt;
            #   alle Parameter sind optional, default keine Angaben: &#039;,,,,,&#039;&lt;br /&gt;
$lightness  # Helligkeit einzelner Elemente (0-100) &amp;quot;&amp;lt;ring&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;minMax&amp;gt;,&amp;lt;unit&amp;gt;,&amp;lt;value&amp;gt;&amp;quot;, optional, default: &amp;quot;50,50,50,40,50&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird &#039;&#039;&#039;$colorFunc&#039;&#039;&#039; nicht angegeben, so wird der Farbwert zwischen &#039;&#039;&#039;$minColor&#039;&#039;&#039; und &#039;&#039;&#039;$maxColor&#039;&#039;&#039; linear interpoliert&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_ring DOIF (1)&lt;br /&gt;
attr di_ring room test20,test5&lt;br /&gt;
attr di_ring uiTable {package ui_Table;; \&lt;br /&gt;
 $SHOWNOSTATE=1}\&lt;br /&gt;
## von 0 bis 20 in Farben von grün (hue:120) bis rot (hue:0)\&lt;br /&gt;
&amp;quot;Umlaufmenge&amp;quot;|ring([heating:pump],0,20,120,0,&amp;quot;l/min&amp;quot;,100)\&lt;br /&gt;
\&lt;br /&gt;
## von 0 bis 3 in Farben von rot (hue:0) bis türkis (hue:180), eine Nachkommastelle, Schriftgröße 170%\&lt;br /&gt;
## Innenring mit Min-, Max-Beschriftung\&lt;br /&gt;
&amp;quot;Wasserdruck&amp;quot;|ring([heating:pressure],0,3,0,180,&amp;quot;bar&amp;quot;,100,undef,&amp;quot;1,font-size:170%,fill:silver;;font-size:50%&amp;quot;,&amp;quot;0,1,1&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Temperaturdarstellung, entspricht dem Funktionsaufruf:\&lt;br /&gt;
## temp_ring ([outdoor:temperature],-20,60,100,&amp;quot;1,font-weight:normal;;font-size:140%&amp;quot;)\&lt;br /&gt;
## Eine Nachkommastelle, Normalschrift, Schriftgröße 140%\&lt;br /&gt;
&amp;quot;Temperatur&amp;quot;|ring([outdoor:temperature,-20,60,undef,undef,&amp;quot;°C&amp;quot;,100,\&amp;amp;temp_hue,&amp;quot;1,font-weight:normal;;font-size:140%&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Lufdruck als Halbring\&lt;br /&gt;
&amp;quot;Luftdruck&amp;quot;|ring([weather:barometer],970,1045,30,90,&amp;quot;hPa&amp;quot;,&amp;quot;100,1&amp;quot;,undef,0)\&lt;br /&gt;
\&lt;br /&gt;
## Co2 als Halbring, Farbgebung als Array mit drei Bereichen, Innenring mit Zeiger\&lt;br /&gt;
&amp;quot;Co2&amp;quot;|ring([livingroom:co2],400,1200,undef,undef,&#039;ppm&#039;,&amp;quot;100,1&amp;quot;,[(600,120,1000,60,1200,0)],0,&#039;0,0,1,5&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:ring_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Temperatur- und Feuchtigkeitsanzeige mit Hilfe der SVG-Funktion &#039;&#039;&#039;temp_hum_ring&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe ist jeweils abhängig vom dargestellten Temperatur- bzw. Feuchtigkeitswert. Die Helligkeit der Farbgebung ist einstellbar:&lt;br /&gt;
[[Datei:Farbskalierung temp_hum_ring_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;temp_hum_ring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
temp_hum_ring ($temp_value,$hum_value,$temp_min,$temp_max,$size, $lightring,$lightnumber,$decFontTemp,$decFontHum)&lt;br /&gt;
&lt;br /&gt;
$temp_value # Temperatur&lt;br /&gt;
$hum_value  # Feuchtigkeit&lt;br /&gt;
$temp_min   # minimale Temperatur, optional, default=-20&lt;br /&gt;
$temp_max   # maximale Temperatur, optional, default=60&lt;br /&gt;
$size       # Größe der Grafik, optional, default=90&lt;br /&gt;
$lightring   # Helligkeit des Ringes (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFontTemp # Temperatur: &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$decFontHum  # Feuchtigkeit: &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_temp_hum_ring DOIF ##&lt;br /&gt;
attr di_temp_hum_ring uiTable {package ui_Table}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;klein&amp;quot;|temp_hum_ring([Aussensensor:temperature],[Aussensensor:humidity],undef,undef,60)\&lt;br /&gt;
&amp;quot;normal&amp;quot;|temp_hum_ring([Aussensensor:temperature],[Aussensensor:humidity])\&lt;br /&gt;
&amp;quot;größer, aufgehellt&amp;quot;|temp_hum_ring([Aussensensor:temperature],[Aussensensor:humidity],undef,undef,100,undef,80)\&lt;br /&gt;
&amp;quot;größer, Ring aufgehellt, Normalschrift&amp;quot;|temp_hum_ring([Aussensensor:temperature],[Aussensensor:humidity],undef,undef,100,80,50,&amp;quot;1,font-weight:normal&amp;quot;,&amp;quot;0,font-weight:normal&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:temp_hum_ring_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige von zwei Temperaturwerten mit Hilfe der SVG-Funktion &#039;&#039;&#039;temp_temp_ring&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe ist jeweils abhängig vom dargestellten Temperaturwert. Die Helligkeit der Farbgebung ist einstellbar:&lt;br /&gt;
[[Datei:Farbskalierung temp_temp_ring_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;temp_temp_ring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
temp_temp_ring ($temp1_value,$temp2_value,$temp_min,$temp_max,$size, $lightring,$lightnumber,$decFontTemp1,$decFontTemp2)&lt;br /&gt;
&lt;br /&gt;
$temp1_value # erster Temperaturwert&lt;br /&gt;
$temp2_value # zweiter Temperaturwert&lt;br /&gt;
$temp_min    # minimale Temperatur, optional, default=-20&lt;br /&gt;
$temp_max    # maximale Temperatur, optional, default=60&lt;br /&gt;
$size        # Größe der Grafik, optional, default=90&lt;br /&gt;
$lightring   # Helligkeit des Ringes (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFontTemp1 # Temperatur1: &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$decFontTemp2 # Temperatur2: &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_temp_temp_ring DOIF ##&lt;br /&gt;
attr di_temp_temp_ring uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;klein, Ring augehellt&amp;quot;|temp_temp_ring([Vorlauf:Temperature],[Ruecklauf:Temperature],15,60,60,80,50)\&lt;br /&gt;
&amp;quot;normal&amp;quot;|temp_temp_ring([Vorlauf:Temperature],[Ruecklauf:Temperature],15,60)\&lt;br /&gt;
&amp;quot;groß, Zahlen aufgehellt&amp;quot;|temp_temp_ring([Vorlauf:Temperature],[Ruecklauf:Temperature],15,60,100,undef,80)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:temp_hum_temp_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige von zwei Zahlenwerten mit Hilfe der universellen SVG-Funktion &#039;&#039;&#039;ring2&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe der dargestellten Werte kann abhängig vom Wert bestimmt werden.&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;ring2&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
ring2 ($value1,$min1,$max1,$minColor1,$maxColor1,$unit1,$size,$colorFunc1,$decFont1,&lt;br /&gt;
       $value2,$min2,$max2,$minColor2,$maxColor2,$unit2,$colorFunc2,$decFont2,&lt;br /&gt;
       $lightness,$icon,$model)&lt;br /&gt;
&lt;br /&gt;
$value1     # darzustellender Wert1&lt;br /&gt;
$min1       # minimaler Wert, optional, default=0&lt;br /&gt;
$max1       # maximaler Wert, optional, default=100&lt;br /&gt;
$minColor1  # Farbe (hue: 0-360) des kleinsten Wertes, optional, default = undef&lt;br /&gt;
$maxColor1  # Farbe (hue: 0-360) des maximalen Wertes, optional, default = undef&lt;br /&gt;
$unit1      # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$size       # Größe der Grafik, optional, default = 100&lt;br /&gt;
$colorFunc1 # Funktion, die zu einem Wert einen Farbwert (hue: 0-360) bestimmt, optional, default = undef&lt;br /&gt;
$decFont1   # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$value2     # darzustellender Wert2&lt;br /&gt;
...&lt;br /&gt;
$decFont2   # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$lightness  # Helligkeit einzelner Elemente (0-100) &amp;quot;&amp;lt;ring&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;minMax&amp;gt;,&amp;lt;unit&amp;gt;,&amp;lt;value&amp;gt;,&amp;lt;icon&amp;gt;&amp;quot;, optional, default: &amp;quot;50,50,50,40,50,40&amp;quot;&lt;br /&gt;
$model      # &#039;&amp;lt;color gradient&amp;gt;,&amp;lt;min/max&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;pointer&amp;gt;,&amp;lt;mode&amp;gt;&#039;,&lt;br /&gt;
            # &amp;lt;color gradient&amp;gt;: 1 für monochrom&lt;br /&gt;
            # &amp;lt;min/max&amp;gt;: Style-SVG-Attribute oder 1 zum Anzeigen der Min-/Maxwerte&lt;br /&gt;
            # &amp;lt;inner ring&amp;gt;: Style-SVG-Attribute oder 1 zum Anzeigen des Innenringes&lt;br /&gt;
            # &amp;lt;pointer&amp;gt;: Breite des Zeigers in Pixel&lt;br /&gt;
            # &amp;lt;mode&amp;gt;: 0 Standard Min. - Max., 1 negativ - Null - positiv, 2 Null - negativ/positiv&lt;br /&gt;
            # alle Parameter sind optional, default keine Angaben: &#039;,,,,,,&#039;&lt;br /&gt;
&lt;br /&gt;
Argumente für den zweiten Wert entsprechend den Argumenten des ersten Wertes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird &#039;&#039;&#039;$colorFunc...&#039;&#039;&#039; nicht angegeben, so wird der Farbwert zwischen &#039;&#039;&#039;$minColor...&#039;&#039;&#039; und &#039;&#039;&#039;$maxColor...&#039;&#039;&#039; linear interpoliert&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_ring2 DOIF ##&lt;br /&gt;
attr di_ring2 uiTable {package ui_Table;;}\&lt;br /&gt;
## Leistungsaufnahme von 0 kW bis 3,6 kW in Farben von grün (hue:120) bis rot (hue:0)\&lt;br /&gt;
## Kapazität von 0 % bis 100 % V in Farben von rot (hue:0) bis grün (hue:120)\&lt;br /&gt;
&amp;quot;Wallbox&amp;quot;| ring2([tesla:Leistung],0,3.6,120,0,&amp;quot;kW&amp;quot;,undef,undef,&amp;quot;1,font-weight:normal&amp;quot;,[tesla:Kapazitaet],0,100,0,120,&amp;quot;%&amp;quot;,undef,&amp;quot;0,font-weight:normal&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Stromstärke von 0 A bis 2 A in Farben von grün (hue:120) bis rot (hue:0)\&lt;br /&gt;
## Spannung von 1 V bis 1.5 V in Farben von rot (hue:0) bis grün (hue:120)\&lt;br /&gt;
## 3 Nachkommastellen, Normalschrift, Schriftgröße 80%  \&lt;br /&gt;
&amp;quot;Akku&amp;quot;| ring2([akku:Strom],0,2,120,0,&amp;quot;A&amp;quot;,undef,undef,&amp;quot;3,font-weight:normal;;font-size:80%&amp;quot;,[akku:Spannung],1,1.5,0,120,&amp;quot;V&amp;quot;,undef,&amp;quot;3,font-weight:normal;;font-size:80%&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:ring2_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition Innenring, Farb-Array, Ringmodi&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_solar DOIF {}&lt;br /&gt;
attr di_solar uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;Farb-Array, ringMode 1&amp;quot;|\&lt;br /&gt;
ring2([zaehler:Produktion],-20,30,undef,undef,&amp;quot;PV kWh&amp;quot;,130,[(-10,0,-0.001,30,10,60,30,90)],&amp;quot;2&amp;quot;,[test:Bezug],-20,30,undef,undef,&amp;quot;Bezug&amp;quot;,[(-10,0,-0.001,30,10,60,30,90)],&amp;quot;2&amp;quot;,undef,undef,&amp;quot;0,1,1,0,1&amp;quot;)\&lt;br /&gt;
&amp;quot;Farbe linear, ringMode 1&amp;quot;|\&lt;br /&gt;
ring2([zeahler:Produktion],-20,30,0,120,&amp;quot;PV kWh&amp;quot;,130,undef,&amp;quot;2&amp;quot;,[test:Bezug],-20,30,0,120,&amp;quot;Bezug&amp;quot;,undef,&amp;quot;2&amp;quot;,undef,undef,&amp;quot;0,1,1,0,1&amp;quot;)\&lt;br /&gt;
&amp;quot;Farbe linear, ringMode 2&amp;quot;|\&lt;br /&gt;
ring2([zaehler:Produktion],0,30,60,120,&amp;quot;PV kWh&amp;quot;,130,undef,&amp;quot;2&amp;quot;,[test:Bezug],-20,0,0,120,&amp;quot;Bezug&amp;quot;,undef,&amp;quot;2&amp;quot;,undef,undef,&amp;quot;0,,,0,2&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:ring2_ringMode.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;icon_ring&#039;&#039;&#039;-Funktionen ====&lt;br /&gt;
===== Farbskalierte Temperaturanzeige mit einem Icon mit Hilfe der SVG-Funktionen &#039;&#039;&#039;icon_temp_ring/icon_temp_mring&#039;&#039;&#039; =====&lt;br /&gt;
Diese Funktionen basieren auf den obigen temp_ring-Funktionen, zusätzlich wird ein SVG-Icon dargestellt. Die Farbe des Icons kann mit @ an den Iconnamen angehängt werden, ansonsten wird die Farbe der Temperatur für das Icon verwendet. Die Größe des Icons kann skaliert werden, ebenso kann die Positionen des Icons verschoben werden.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_temp_ring/icon_temp_mring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_temp_ring/icon_temp_mring ($icon,$temp_value,$temp_min,$temp_max,$size,$lightring,$lightnumber,$decFont) &lt;br /&gt;
&lt;br /&gt;
$icon        # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position,Rotation&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position, Rotation (0-360) sind optional&lt;br /&gt;
$temp_value  # Temperatur&lt;br /&gt;
$temp_min,   # minimale Temperatur, optional, default=-20&lt;br /&gt;
$temp_max,   # maximale Temperatur, optional, default=60&lt;br /&gt;
$size,       # Größe der Grafik, optional, default=80&lt;br /&gt;
$lightring,  # Helligkeit des Ringes (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFont     # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_Heizung_temp DOIF ##&lt;br /&gt;
attr di_Heizung_temp uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
icon_temp_ring(&amp;quot;temp_outside&amp;quot;,[vaillant:Aussentemp],-15,40)|\&lt;br /&gt;
icon_temp_mring(([vaillant:Flame] eq &amp;quot;off&amp;quot;?&amp;quot;sani_boiler_temp\@white&amp;quot;:&amp;quot;sani_boiler_temp\@Darkorange&amp;quot;),[vaillant:Vorlauf],15,70)|\&lt;br /&gt;
icon_temp_mring(([vaillant:Pumpenstatus] eq &amp;quot;4&amp;quot; ? &amp;quot;sani_buffer_temp_down\@Darkorange&amp;quot; : &amp;quot;sani_buffer_temp_down\@white&amp;quot;),[vaillant:WWSpeicher],15,70)|\&lt;br /&gt;
icon_temp_mring(([Zirk] eq &amp;quot;off&amp;quot;?&amp;quot;sani_pump\@white&amp;quot;:&amp;quot;sani_pump\@Darkorange&amp;quot;),[ESPEasy_ESP_Temp_Zirkulation:Temperature],15,70)|\&lt;br /&gt;
icon_temp_mring(([vaillant:Pumpenstatus] eq &amp;quot;on&amp;quot; ? &amp;quot;sani_floor_heating\@Darkorange&amp;quot; : &amp;quot;sani_floor_heating_neutral\@white&amp;quot;),[ESPEasy_ESP_Temp_Vorlauf:Temperature],15,70)|\&lt;br /&gt;
icon_temp_mring(&amp;quot;sani_floor_heating_neutral\@white&amp;quot;,[ESPEasy_ESP_Temp_Keller_Ruecklauf:Temperature],15,70)|&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_temp_ring_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Feuchtigkeitsanzeige mit einem Icon mit Hilfe der SVG-Funktionen &#039;&#039;&#039;icon_hum_ring/icon_hum_mring&#039;&#039;&#039; =====&lt;br /&gt;
Diese Funktionen basieren auf den obigen hum_ring-Funktionen, zusätzlich wird ein SVG-Icon dargestellt. Die Farbe des Icons kann mit @ an den Iconnamen angehängt werden, ansonsten wird die Farbe der Feuchtigkeit für das Icon verwendet. Die Größe des Icons kann skaliert werden, ebenso kann die Positionen des Icons verschoben werden. &lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_hum_ring/icon_hum_mring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_hum_ring/icon_hum_mring ($icon,$hum_value,$size,$lightring,$lightnumber,$decFont) &lt;br /&gt;
&lt;br /&gt;
$icon        # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position,Rotation&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position, Rotation sind optional&lt;br /&gt;
$hum_value   # Feuchtigkeit&lt;br /&gt;
$size        # Größe der Grafik, optional, default=80&lt;br /&gt;
$lightring   # Helligkeit des Ringes (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFont     # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_icon_hum_ring DOIF ##&lt;br /&gt;
attr di_icon_hum_ring room test5&lt;br /&gt;
attr di_icon_hum_ring uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;klein ohne Farbverlauf&amp;quot;|icon_hum_mring(&amp;quot;weather_humidity&amp;quot;,[Aussensensor:humidity],60)\&lt;br /&gt;
&amp;quot;normal groß mit Farbverlauf&amp;quot;|icon_hum_ring(&amp;quot;weather_humidity&amp;quot;,[Aussensensor:humidity])\&lt;br /&gt;
&amp;quot;groß ohne Farbverlauf aufgehellt&amp;quot;|icon_hum_mring(&amp;quot;weather_humidity&amp;quot;,[Aussensensor:humidity],100,80)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_hum_ring_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige eines Icons mit einem Zahlenwert mit Hilfe der universellen SVG-Funktion &#039;&#039;&#039;icon_ring/icon_mring/icon_uring&#039;&#039;&#039; =====&lt;br /&gt;
Diese Funktionen basieren auf der universellen ring-Funktion. Die Farbe des dargestellten Icons und des Wertes kann abhängig vom Wert bestimmt werden. Die Funktion &#039;&#039;&#039;icon_ring&#039;&#039;&#039; stellt den Farbring mit Farbverlauf dar, die Funktion &#039;&#039;&#039;icon_mring&#039;&#039;&#039; stellt den Farbring einfarbig dar. Die universelle Funktion &#039;&#039;&#039;icon_uring&#039;&#039;&#039; kann über den Parameter &#039;&#039;&#039;$model&#039;&#039;&#039; das Erscheinungsbild der Grafik verändern.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_ring/icon_mring/icon_uring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_ring ($icon,$value,$min,$max,$minColor,$maxColor, $unit,$decFont,$size,$colorRef,$lightness,$model)&lt;br /&gt;
&lt;br /&gt;
icon_mring ($icon,$value,$min,$max,$minColor,$maxColor, $unit,$decFont,$size,$colorRef,$lightness)&lt;br /&gt;
&lt;br /&gt;
icon_uring ($model,$icon,$value,$min,$max,$minColor,$maxColor, $unit,$decFont,$size,$colorRef,$lightness)&lt;br /&gt;
&lt;br /&gt;
$icon      # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position,Rotation&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position, Rotation sind optional&lt;br /&gt;
$value     # darzustellender Wert&lt;br /&gt;
$min       # minimaler Wert, optional, default=0&lt;br /&gt;
$max       # maximaler Wert, optional, default=100&lt;br /&gt;
$minColor  # Farbe (hue: 0-360) des kleinsten Wertes, optional, default = undef&lt;br /&gt;
$maxColor  # Farbe (hue: 0-360) des maximalen Wertes, optional, default = undef&lt;br /&gt;
$unit      # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$decFont   # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Style-SVG-Attribute Wert&amp;gt;,&amp;lt;Style-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$size      # Größe der Grafik, optional, default = 100&lt;br /&gt;
$colorRef  # Referenz auf eine Funktion, die zu einem Wert einen Farbwert (hue: 0-360) bestimmt, oder eine Referenz auf eine Arrayliste mit Grenzwerten und Farben, optional, default = undef&lt;br /&gt;
$lightness  # Helligkeit einzelner Elemente (0-100) &amp;quot;&amp;lt;ring&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;minMax&amp;gt;,&amp;lt;unit&amp;gt;,&amp;lt;value&amp;gt;,&amp;lt;icon&amp;gt;&amp;quot;, optional, default: &amp;quot;50,50,50,40,50,40&amp;quot;&lt;br /&gt;
$model      # &#039;&amp;lt;color gradient&amp;gt;,&amp;lt;min/max&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;pointer&amp;gt;,&amp;lt;mode&amp;gt;&#039;,&lt;br /&gt;
            # &amp;lt;color gradient&amp;gt;: 1 für monochrom&lt;br /&gt;
            # &amp;lt;min/max&amp;gt;: Style-SVG-Attribute oder 1 zum Anzeigen der Min-/Maxwerte&lt;br /&gt;
            # &amp;lt;inner ring&amp;gt;: Style-SVG-Attribute oder 1 zum Anzeigen des Innenringes&lt;br /&gt;
            # &amp;lt;pointer&amp;gt;: Breite des Zeigers in Pixel&lt;br /&gt;
            # &amp;lt;mode&amp;gt;: 0 Standard Min. - Max., 1 negativ - Null - positiv, 2 Null - negativ/positiv&lt;br /&gt;
            # alle Parameter sind optional, default keine Angaben: &#039;,,,,,,&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird &#039;&#039;&#039;$colorRef&#039;&#039;&#039; nicht angegeben, so wird der Farbwert zwischen &#039;&#039;&#039;$minColor&#039;&#039;&#039; und &#039;&#039;&#039;$maxColor&#039;&#039;&#039; linear interpoliert&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_icon_ring DOIF ##&lt;br /&gt;
attr di_icon_ring uiTable {package ui_Table}\&lt;br /&gt;
\&lt;br /&gt;
icon_ring (&#039;sani_floor_heating_neutral&#039;,[Heizenergie:Vortag_hc],0,150,120,0,&#039;kWh&#039;)|\&lt;br /&gt;
icon_mring (&#039;fuel&#039;,[Tankstelle:Diesel],1.10,1.30,120,0,&#039;€&#039;,2)|\&lt;br /&gt;
icon_uring (&#039;0,1,1&#039;,&amp;quot;air&amp;quot;,[ESPEasy_Eingang_CO2:PPM],400,1200,undef,undef,&#039;ppm&#039;,0,100,[(600,120,1000,60,1200,0)])|\&lt;br /&gt;
icon_uring (&#039;0,1&#039;,&#039;Zisterne&#039;,([Wasserzisterne]/3.4),0,100,0,120,&#039;%&#039;,0)##/\&lt;br /&gt;
\&lt;br /&gt;
icon_uring (&#039;1,1,0,8&#039;,&amp;quot;measure_water_meter&amp;quot;,[Wasserverbrauch:heute],0,600,120,0,&#039;l&#039;,0)|\&lt;br /&gt;
icon_uring (&#039;0,fill:white,opacity:0.4&#039;,([vaillant:Pumpenstatus] eq &#039;4&#039; ? &#039;sani_buffer_temp_down@Darkorange&#039; : &#039;sani_buffer_temp_down@white&#039;),[vaillant:Umlaufmenge],0,20,120,0,&#039;l/min&#039;)|\&lt;br /&gt;
icon_uring(&#039;0,1,1,4&#039;,&#039;weather_barometric_pressure&#039;,[vaillant:Wasserdruck],0,3,undef,undef,&#039;bar&#039;,1,100,[(0.8,0,1,60,1.5,120,1.7,60,3,0)])|\&lt;br /&gt;
icon_uring(&#039;0,opacity:0.8,1,6&#039;,&#039;sani_water_tap&#039;,[vaillant:HwcHours_hoursum2_value],0,2000,120,0,&#039;h&#039;,0)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_ring_bsp.png|ohne|mini]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Temperatur- und Feuchtigkeitsanzeige mit einem Icon mit Hilfe der SVG-Funktion &#039;&#039;&#039;icon_temp_hum_ring&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe ist jeweils abhängig vom dargestellten Temperatur- bzw. Feuchtigkeitswert. Die Helligkeit der Farbgebung ist einstellbar:&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_temp_hum_ring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_temp_hum_ring ($icon,$temp_value,$hum_value,$temp_min,$temp_max,$size, $lightring,$lightnumber,$decFontTemp,$decFontHum)&lt;br /&gt;
&lt;br /&gt;
$icon      # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position,Rotation&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position, Rotation sind optional&lt;br /&gt;
$temp_value # Temperatur&lt;br /&gt;
$hum_value  # Feuchtigkeit&lt;br /&gt;
$temp_min   # minimale Temperatur, optional, default=-20&lt;br /&gt;
$temp_max   # maximale Temperatur, optional, default=60&lt;br /&gt;
$size       # Größe der Grafik, optional, default=90&lt;br /&gt;
$lightring   # Helligkeit des Ringes (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFontTemp # Temperatur: &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$decFontHum  # Feuchtigkeit: &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_icon_temp_hum_ring DOIF ##&lt;br /&gt;
attr di_icon_temp_hum_ring uiTable {package ui_Table}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;normal&amp;quot;|icon_temp_hum_ring(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature],[Aussensensor:humidity])\&lt;br /&gt;
&amp;quot;mit Normalschrift&amp;quot;|icon_temp_hum_ring(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature],[Aussensensor:humidity], undef,undef,undef,undef,undef,&amp;quot;1,font-weight:normal&amp;quot;,&amp;quot;0,font-weight:normal&amp;quot;)\&lt;br /&gt;
&amp;quot;größer aufgehellt&amp;quot;|icon_temp_hum_ring(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature],[Aussensensor:humidity], undef,undef,120,undef,80)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_temp_hum_ring.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige von zwei Temperaturwerten mit einem Icon mit Hilfe der SVG-Funktion &#039;&#039;&#039;icon_temp_temp_ring&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe ist jeweils abhängig vom dargestellten Temperaturwert. Die Helligkeit der Farbgebung ist einstellbar:&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_temp_temp_ring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_temp_temp_ring ($icon,$temp1_value,$temp2_value,$temp_min,$temp_max,$size, $lightring,$lightnumber,$decFontTemp1,$decFontTemp2)&lt;br /&gt;
&lt;br /&gt;
$icon        # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position,Rotation&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position, Rotation sind optional&lt;br /&gt;
$temp1_value # erster Temperaturwert&lt;br /&gt;
$temp2_value # zweiter Temperaturwert&lt;br /&gt;
$temp_min    # minimale Temperatur, optional, default=-20&lt;br /&gt;
$temp_max    # maximale Temperatur, optional, default=60&lt;br /&gt;
$size        # Größe der Grafik, optional, default=90&lt;br /&gt;
$lightring   # Helligkeit des Ringes (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFontTemp1 # Temperatur1: &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$decFontTemp2 # Temperatur2: &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_icon_temp_temp_ring DOIF ##&lt;br /&gt;
attr di_icon_temp_temp_ring uiTable {package ui_Table}\&lt;br /&gt;
## Größe 120%\&lt;br /&gt;
&amp;quot;FB-Heizung&amp;quot;|icon_temp_temp_ring(([vaillant:Pumpenstatus] eq &amp;quot;on&amp;quot; ? &amp;quot;sani_floor_heating\@Darkorange&amp;quot; : &amp;quot;sani_floor_heating_neutral\@white&amp;quot;),[ESPEasy_ESP_Temp_Vorlauf:Temperature],[ESPEasy_ESP_Temp_Keller_Ruecklauf:Temperature],15,70,120)\&lt;br /&gt;
\&lt;br /&gt;
## Größe 120%, Normalschrift\&lt;br /&gt;
&amp;quot;Temperatur&amp;quot;,&amp;quot;Taupunkt&amp;quot;|icon_temp_temp_ring(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature],[Aussensensor:dewpoint],undef,undef,120,undef,undef,&amp;quot;1,font-weight:normal&amp;quot;,&amp;quot;1,font-weight:normal&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_temp_temp_ring.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige von zwei Zahlenwerten mit einem Icon mit Hilfe der universellen SVG-Funktion &#039;&#039;&#039;icon_ring2&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe der dargestellten Werte kann abhängig vom Wert bestimmt werden.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_ring2&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_ring2 ($icon,$value1,$min1,$max1,$minColor1,$maxColor1,$unit1,$size,$colorFunc1,$decFont1, $value2,$min2,$max2,$minColor2,$maxColor2,$unit2,$colorFunc2,$decFont2,$lightnesss,$model)&lt;br /&gt;
&lt;br /&gt;
$icon       # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position,Rotation&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position, Rotation sind optional&lt;br /&gt;
$value1     # darzustellender Wert1&lt;br /&gt;
$min1       # minimaler Wert, optional, default=0&lt;br /&gt;
$max1       # maximaler Wert, optional, default=100&lt;br /&gt;
$minColor1  # Farbe (hue: 0-360) des kleinsten Wertes, optional, default = undef&lt;br /&gt;
$maxColor1  # Farbe (hue: 0-360) des maximalen Wertes, optional, default = undef&lt;br /&gt;
$unit1      # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$size       # Größe der Grafik, optional, default = 100&lt;br /&gt;
$colorFunc1 # Funktion, die zu einem Wert einen Farbwert (hue: 0-360) bestimmt, optional, default = undef&lt;br /&gt;
$decFont1   # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$value2     ## darzustellender Wert2&lt;br /&gt;
...&lt;br /&gt;
$unit2      # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$colorFunc2 # Funktion, die zu einem Wert einen Farbwert (hue: 0-360) bestimmt, optional, default = undef&lt;br /&gt;
$decFont2   # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$lightness  # Helligkeit einzelner Elemente (0-100) &amp;quot;&amp;lt;ring&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;minMax&amp;gt;,&amp;lt;unit&amp;gt;,&amp;lt;value&amp;gt;,&amp;lt;icon&amp;gt;&amp;quot;, optional, default: &amp;quot;50,50,50,40,50,40&amp;quot;&lt;br /&gt;
$model      # &#039;&amp;lt;color gradient&amp;gt;,&amp;lt;min/max&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;pointer&amp;gt;,&amp;lt;mode&amp;gt;&#039;,&lt;br /&gt;
            # &amp;lt;color gradient&amp;gt;: 1 für monochrom&lt;br /&gt;
            # &amp;lt;min/max&amp;gt;: Style-SVG-Attribute oder 1 zum Anzeigen der Min-/Maxwerte&lt;br /&gt;
            # &amp;lt;inner ring&amp;gt;: Style-SVG-Attribute oder 1 zum Anzeigen des Innenringes&lt;br /&gt;
            # &amp;lt;pointer&amp;gt;: Breite des Zeigers in Pixel&lt;br /&gt;
            # &amp;lt;mode&amp;gt;: 0 Standard Min. - Max., 1 negativ - Null - positiv, 2 Null - negativ/positiv&lt;br /&gt;
            # alle Parameter sind optional, default keine Angaben: &#039;,,,,,,&#039;&lt;br /&gt;
&lt;br /&gt;
Argumente für den zweiten Wert entsprechend den Argumenten des ersten Wertes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird &#039;&#039;&#039;$colorFunc...&#039;&#039;&#039; nicht angegeben, so wird der Farbwert zwischen &#039;&#039;&#039;$minColor...&#039;&#039;&#039; und &#039;&#039;&#039;$maxColor...&#039;&#039;&#039; linear interpoliert.&lt;br /&gt;
&lt;br /&gt;
Bei der Farbangabe des Icons beim Übergabeparameter $icon wird mit &#039;&#039;&#039;\@colorVal2&#039;&#039;&#039; das Icon mit der Farbe des zweiten Wertes eingefärbt. Bei keiner Farbangabe oder &#039;&#039;&#039;\@colorVal1&#039;&#039;&#039; wird das Icon mit der Farbe des ersten Wertes eingefärbt. Ansonsten gilt die allgemeine FHEM-Syntax für Farbgebung von Icons angehängt mit &#039;&#039;&#039;\@&#039;&#039;&#039;.&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_icon_ring2 DOIF ##&lt;br /&gt;
attr di_icon_ring2 uiTable {package ui_Table;;\&lt;br /&gt;
\&lt;br /&gt;
sub himmelsrichtung {\&lt;br /&gt;
my ($richtung)=@_;;\&lt;br /&gt;
my $element=int($richtung/22.5);;\##/&lt;br /&gt;
my @h=(qw&amp;quot;N NNO NO ONO O OSO SO SSO S SSW SW WSW W WNW NW NNW&amp;quot;);;\&lt;br /&gt;
return($h[$element]);;\&lt;br /&gt;
}\&lt;br /&gt;
}\&lt;br /&gt;
&amp;quot;Wallbox&amp;quot;| icon_ring2(&amp;quot;car,1.5,0,-3&amp;quot;,[tesla:Leistung],0,3.6,120,0,&amp;quot;kW&amp;quot;,120,undef,&amp;quot;1,font-weight:normal&amp;quot;,[tesla:Kapazitaet],0,100,0,120,&amp;quot;%&amp;quot;,undef,&amp;quot;0,font-weight:normal&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Wind&amp;quot;|icon_ring2(([Wind:Geschwindigkeit]&amp;gt;0 ? &amp;quot;wind&amp;quot;:&amp;quot;no_wind&amp;quot;).&amp;quot;,1,0,0,&amp;quot;.[Wind:Richtung],[Wind:Geschwindigkeit],0,50,120,0,&amp;quot;km/h&amp;quot;,120,undef,1,[Wind:Richtung],361,361,220,220,([Wind:Geschwindigkeit]&amp;gt;0?himmelsrichtung([Wind:Richtung]):&amp;quot;--&amp;quot;),undef,0)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;quot;|icon_ring2([zaehler:l-Produktion] &amp;gt; 0 ? &amp;quot;sani_solar\@colorVal1&amp;quot;:&amp;quot;fa_bolt\@colorVal2&amp;quot;,[zaehler:l-Produktion],0,3.6,20,120,&amp;quot;PV kW&amp;quot;,150,undef,&amp;quot;1,,font-size:50%;fill:white&amp;quot;,[zaehler:l-Bezug,0],0,2,120,0,&amp;quot;Netz kW&amp;quot;,undef,&amp;quot;1,,font-size:50%;fill:white&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_ring2.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;bar&#039;&#039;&#039;-Funktionen ====&lt;br /&gt;
===== Farbskalierte Anzeige der Temperatur in Balkenform mit Hilfe der SVG-Funktionen &#039;&#039;&#039;temp_bar/temp_mbar&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe der dargestellten Temperatur ist abhängig vom Temperaturwert. Die Helligkeit der Farbgebung ist einstellbar. Bei der &#039;&#039;&#039;temp_mbar&#039;&#039;&#039;-SVG-Funktion wird der Balken einfarbig dargestellt.&lt;br /&gt;
&lt;br /&gt;
Farbskalierung der &#039;&#039;&#039;temp_bar&#039;&#039;&#039;-SVG-Funktion:&lt;br /&gt;
[[Datei:Farbskalierung temp_bar_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
Farbskalierung der &#039;&#039;&#039;temp_mbar&#039;&#039;&#039;-SVG-Funktion:&lt;br /&gt;
[[Datei:Farbskalierung temp_mbar_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;temp_bar/temp_mbar&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
temp_bar/temp_mbar ($temp_value,$temp_min,$temp_max, $header,$width,$height,$size, $light,$lightnumber,$decFont)&lt;br /&gt;
&lt;br /&gt;
$temp_value  # Temperaturwert&lt;br /&gt;
$temp_min    # minimale Temperatur, optional, default=-20&lt;br /&gt;
$temp_max    # maximale Temperatur, optional, default=60&lt;br /&gt;
$header      # Überschrift, optional, default= undef (keine)&lt;br /&gt;
$width       # Breite der Grafik, optional, default=63&lt;br /&gt;
$height      # Höhe der Grafik, optional, default=60&lt;br /&gt;
$size        # Größe der Grafik, optional, default=100&lt;br /&gt;
$light       # Helligkeit der Grafik (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFont     # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional, default = 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_temp_bar DOIF ##&lt;br /&gt;
attr di_temp_bar uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;standard&amp;quot;|temp_bar([Aussensensor:temperature])\&lt;br /&gt;
&amp;quot;heller&amp;quot;|temp_bar([Aussensensor:temperature],undef,undef,undef,undef,undef,undef,80)\&lt;br /&gt;
&amp;quot;monochrom&amp;quot;|temp_mbar([Aussensensor:temperature])\&lt;br /&gt;
&amp;quot;kleiner&amp;quot;|temp_bar([Aussensensor:temperature],undef,undef,undef,undef,undef,80)\&lt;br /&gt;
&amp;quot;mit Überschrift&amp;quot;|temp_bar([Aussensensor:temperature],undef,undef,&amp;quot;Außen&amp;quot;)\&lt;br /&gt;
&amp;quot;hoch&amp;quot;|temp_bar([Aussensensor:temperature],undef,undef,undef,undef,100)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:temp_bar_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige der Feuchtigkeit in Balkenform mit Hilfe der SVG-Funktionen &#039;&#039;&#039;hum_bar/hum_mbar&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe der dargestellten Feuchtigkeit ist abhängig vom Feuchtigkeitswert. Die Helligkeit der Farbgebung ist einstellbar. Bei der &#039;&#039;&#039;hum_mbar&#039;&#039;&#039;-SVG-Funktion wird der Balken einfarbig dargestellt.&lt;br /&gt;
&lt;br /&gt;
Farbskalierung der &#039;&#039;&#039;hum_bar&#039;&#039;&#039;-SVG-Funktion:&lt;br /&gt;
[[Datei:Farbskalierung hum_bar_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
Farbskalierung der &#039;&#039;&#039;hum_mbar&#039;&#039;&#039;-SVG-Funktion:&lt;br /&gt;
[[Datei:Farbskalierung hum_mbar_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;hum_bar/hum_mbar&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
hum_bar/hum_mbar ($hum_value,$header,$width,$height,$size, $light,$lightnumber,$decFont)&lt;br /&gt;
&lt;br /&gt;
$hum_value   # Feuchtigkeitswert&lt;br /&gt;
$header      # Überschrift, optional, default = undef (keine)&lt;br /&gt;
$width       # Breite der Grafik, optional, default=63&lt;br /&gt;
$height      # Höhe der Grafik, optional, default=80&lt;br /&gt;
$size        # Größe der Grafik, optional, default=100&lt;br /&gt;
$light       # Helligkeit des der Grafik (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFont     # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional, default = 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_hum_bar DOIF ##&lt;br /&gt;
attr di_hum_bar uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;standard&amp;quot;|hum_bar([Aussensensor:humidity])\&lt;br /&gt;
&amp;quot;heller&amp;quot;|hum_bar([Aussensensor:humidity],undef,undef,undef,undef,80)\&lt;br /&gt;
&amp;quot;monochrom&amp;quot;|hum_mbar([Aussensensor:humidity])\&lt;br /&gt;
&amp;quot;kleiner&amp;quot;|hum_bar([Aussensensor:humidity],undef,undef,undef,80)\&lt;br /&gt;
&amp;quot;mit Überschrift&amp;quot;|hum_bar([Aussensensor:humidity],&amp;quot;Außen&amp;quot;)\&lt;br /&gt;
&amp;quot;hoch&amp;quot;|hum_bar([Aussensensor:humidity],undef,undef,100)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:hum_bar_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige eines Zahlenwertes mit Hilfe der universellen SVG-Funktion &#039;&#039;&#039;bar&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe des dargestellten Wertes kann abhängig vom Wert bestimmt werden.&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;bar&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
bar ($value,$min,$max,$header,$minColor,$maxColor,$unit,$width, $height,$size,$colorFunc,$decFont,$gradient,$light,$lightnumber)&lt;br /&gt;
&lt;br /&gt;
$value     # darzustellender Wert&lt;br /&gt;
$min       # minimaler Wert, optional, default=0&lt;br /&gt;
$max       # maximaler Wert, optional, default=100&lt;br /&gt;
$header    # Überschrift, optional, default = undef (keine)&lt;br /&gt;
$minColor  # Farbe (hue: 0-360) des kleinsten Wertes, optional, default = undef&lt;br /&gt;
$maxColor  # Farbe (hue: 0-360) des maximalen Wertes, optional, default = undef&lt;br /&gt;
$unit      # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$width     # Breite der Grafik, optional, default = 63&lt;br /&gt;
$height    # Höhe der Grafik, optional, default = 60&lt;br /&gt;
$size      # Größe der Grafik, optional, default = 100&lt;br /&gt;
$colorFunc # Funktion, die zu einem Wert einen Farbwert (hue: 0-360) bestimmt, optional, default = undef&lt;br /&gt;
$decFont   # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional, default = 1&lt;br /&gt;
$gradient  # Farbverlauf, optional, undef mit Farbverlauf, 1 ohne Farbverlauf, default = undef&lt;br /&gt;
$light     # Helligkeit der Grafik (light:0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (light:0-100), optional, default=50&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird &#039;&#039;&#039;$colorFunc&#039;&#039;&#039; nicht angegeben, so wird der Farbwert zwischen &#039;&#039;&#039;$minColor&#039;&#039;&#039; und &#039;&#039;&#039;$maxColor&#039;&#039;&#039; linear interpoliert&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
{package ui_Table}&lt;br /&gt;
defmod di_bar DOIF ##&lt;br /&gt;
attr di_bar uiTable {package ui_Table}\&lt;br /&gt;
## von 0 bis 20 in Farben von grün (hue:120) bis rot (hue:0)\&lt;br /&gt;
&amp;quot;Umlaufmenge&amp;quot;|bar([heizung:Umlaufmenge],0,20,&amp;quot;Umlauf&amp;quot;,120,0,&amp;quot;l/min&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## von 0 bis 3 in Farben von rot (hue:0) bis türkis (hue:180)\&lt;br /&gt;
&amp;quot;Wasserdruck&amp;quot;|bar([heizung:Wasserdruck],0,3,undef,0,180,&amp;quot;bar&amp;quot;undef,70,undef,undef,&amp;quot;1,font-size:130%;;font-weight:normal&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Temperaturdarstellung, entspricht dem Funktionsaufruf:\&lt;br /&gt;
## temp_bar ([Aussensensor:temperature],-20,60)\&lt;br /&gt;
&amp;quot;Temperatur&amp;quot;|bar([Aussensensor:temperature],-20,60,undef,undef,undef,&amp;quot;°C&amp;quot;,undef,undef,undef,\&amp;amp;temp_hue)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:bar_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;icon_bar&#039;&#039;&#039;-Funktionen ====&lt;br /&gt;
===== Farbskalierte Anzeige der Temperatur in Balkenform mit Hilfe der SVG-Funktion &#039;&#039;&#039;icon_temp_bar/icon_temp_mbar&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe der dargestellten Temperatur ist abhängig vom Temperaturwert. Die Helligkeit der Farbgebung ist einstellbar. Bei der &#039;&#039;&#039;icon_temp_mbar&#039;&#039;&#039;-SVG-Funktion wird der Balken einfarbig dargestellt.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_temp_bar/icon_temp_mbar&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_temp_bar/icon_temp_mbar ($icon,$temp_value,$temp_min,$temp_max, $header,$width,$height,$size,$light,$lightnumber,$decFont)&lt;br /&gt;
&lt;br /&gt;
$icon        # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position sind optional&lt;br /&gt;
$temp_value  # Temperaturwert&lt;br /&gt;
$temp_min    # minimale Temperatur, optional, default=-20&lt;br /&gt;
$temp_max    # maximale Temperatur, optional, default=60&lt;br /&gt;
$header      # Überschrift, optional, default= undef (keine)&lt;br /&gt;
$width       # Breite der Grafik, optional, default=63&lt;br /&gt;
$height      # Höhe der Grafik, optional, default=75&lt;br /&gt;
$size        # Größe der Grafik, optional, default=100&lt;br /&gt;
$light       # Helligkeit der Grafik (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFont     # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional, default = 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_icon_temp_bar DOIF ##&lt;br /&gt;
attr di_icon_temp_bar room test10&lt;br /&gt;
attr di_icon_temp_bar uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;standard&amp;quot;|icon_temp_bar(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature])\&lt;br /&gt;
&amp;quot;heller&amp;quot;|icon_temp_bar(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature],undef,undef,undef,undef,undef,undef,80)\&lt;br /&gt;
&amp;quot;monochrom&amp;quot;|icon_temp_mbar(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature])\&lt;br /&gt;
&amp;quot;kleiner&amp;quot;|icon_temp_bar(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature],undef,undef,undef,undef,undef,80)\&lt;br /&gt;
&amp;quot;mit Überschrift&amp;quot;|icon_temp_bar(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature],undef,undef,&amp;quot;Außen&amp;quot;)\&lt;br /&gt;
&amp;quot;hoch&amp;quot;|icon_temp_bar(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature],undef,undef,undef,undef,100)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_temp_bar_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige der Feuchtigkeit in Balkenform mit Hilfe der SVG-Funktionen &#039;&#039;&#039;icon_hum_bar/icon_hum_mbar&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe der dargestellten Feuchtigkeit ist abhängig vom Feuchtigkeitswert. Die Helligkeit der Farbgebung ist einstellbar. Bei der &#039;&#039;&#039;icon_hum_mbar&#039;&#039;&#039;-SVG-Funktion wird der Balken einfarbig dargestellt.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_hum_bar/icon_hum_mbar&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_hum_bar/icon_hum_mbar ($icon,$hum_value,$header,$width,$height,$size, $light,$lightnumber,$decFont)&lt;br /&gt;
&lt;br /&gt;
$icon        # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position sind optional&lt;br /&gt;
$hum_value   # Temperaturwert&lt;br /&gt;
$header      # Überschrift, optional, default = undef (keine)&lt;br /&gt;
$width       # Breite der Grafik, optional, default=63&lt;br /&gt;
$height      # Höhe der Grafik, optional, default=75&lt;br /&gt;
$size        # Größe der Grafik, optional, default=100&lt;br /&gt;
$light       # Helligkeit des der Grafik (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFont     # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional, default = 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_icon_hum_bar DOIF ##&lt;br /&gt;
attr di_icon_hum_bar uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;standard&amp;quot;|icon_hum_bar(&amp;quot;temperature_humidity&amp;quot;,[Aussensensor:humidity])\&lt;br /&gt;
&amp;quot;heller&amp;quot;|icon_hum_bar(&amp;quot;temperature_humidity&amp;quot;,[Aussensensor:humidity],undef,undef,undef,undef,80)\&lt;br /&gt;
&amp;quot;monochrom&amp;quot;|icon_hum_mbar(&amp;quot;temperature_humidity&amp;quot;,[Aussensensor:humidity])\&lt;br /&gt;
&amp;quot;kleiner&amp;quot;|icon_hum_bar(&amp;quot;temperature_humidity&amp;quot;,[Aussensensor:humidity],undef,undef,undef,80)\&lt;br /&gt;
&amp;quot;mit Überschrift&amp;quot;|icon_hum_bar(&amp;quot;temperature_humidity&amp;quot;,[Aussensensor:humidity],&amp;quot;Außen&amp;quot;)\&lt;br /&gt;
&amp;quot;hoch&amp;quot;|icon_hum_bar(&amp;quot;temperature_humidity&amp;quot;,[Aussensensor:humidity],undef,undef,100)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_hum_bar_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige eines Zahlenwertes mit Hilfe der universellen SVG-Funktionen &#039;&#039;&#039;icon_bar/icon_mbar&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe des dargestellten Wertes und des Icons kann abhängig vom Wert bestimmt werden. Bei der &#039;&#039;&#039;icon_mbar&#039;&#039;&#039;-SVG-Funktion wird der Balken einfarbig dargestellt.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_bar/icon_mbar&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_bar ($icon,$value,$min,$max,$minColor,$maxColor,$unit,$decfont,$header,$width,$height,$size, $colorFunc,$light,$lightnumber)&lt;br /&gt;
&lt;br /&gt;
$icon      # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position,Rotation&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position, Rotation (0-360) sind optional&lt;br /&gt;
$value     # darzustellender Wert&lt;br /&gt;
$min       # minimaler Wert, optional, default=0&lt;br /&gt;
$max       # maximaler Wert, optional, default=100&lt;br /&gt;
$header    # Überschrift, optional, default = undef (keine)&lt;br /&gt;
$minColor  # Farbe (hue: 0-360) des kleinsten Wertes, optional, default = undef&lt;br /&gt;
$maxColor  # Farbe (hue: 0-360) des maximalen Wertes, optional, default = undef&lt;br /&gt;
$unit      # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$decFont   # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional, default = 1&lt;br /&gt;
$width     # Breite der Grafik, optional, default = 63&lt;br /&gt;
$height    # Höhe der Grafik, optional, default = 75&lt;br /&gt;
$size      # Größe der Grafik, optional, default = 100&lt;br /&gt;
$colorFunc # Funktion, die zu einem Wert einen Farbwert (hue: 0-360) bestimmt, optional, default = undef&lt;br /&gt;
$light     # Helligkeit der Grafik (light:0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (light:0-100), optional, default=50&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird &#039;&#039;&#039;$colorFunc&#039;&#039;&#039; nicht angegeben, so wird der Farbwert zwischen &#039;&#039;&#039;$minColor&#039;&#039;&#039; und &#039;&#039;&#039;$maxColor&#039;&#039;&#039; linear interpoliert&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_icon_bar_bsp DOIF ##&lt;br /&gt;
attr di_icon_bar_bsp uiTable {package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
icon_bar (&amp;quot;fuel&amp;quot;,[Tankstelle:Diesel],1.10,1.30,120,0,&amp;quot;€&amp;quot;,2)|\&lt;br /&gt;
icon_bar (&amp;quot;air&amp;quot;,[ESPEasy_Eingang_CO2:PPM],400,1200,120,0,&amp;quot;ppm&amp;quot;,0)|\&lt;br /&gt;
icon_bar (&amp;quot;Zisterne&amp;quot;,([Wasserzisterne]/3.4),0,100,0,120,&amp;quot;%&amp;quot;,0)|\&lt;br /&gt;
icon_bar (([vaillant:Pumpenstatus] eq &amp;quot;off&amp;quot; ? &amp;quot;sani_buffer_temp_down\@Darkorange&amp;quot; : &amp;quot;sani_buffer_temp_down\@white&amp;quot;),[vaillant:Umlaufmenge],0,20,120,0,&amp;quot;l/min&amp;quot;)\&lt;br /&gt;
icon_bar (&amp;quot;measure_water_meter&amp;quot;,[Wasserverbrauch:heute],0,600,120,0,&amp;quot;l&amp;quot;,0)|\&lt;br /&gt;
icon_bar (&amp;quot;weather_barometric_pressure&amp;quot;,[vaillant:Wasserdruck],0,3,0,180,&amp;quot;bar&amp;quot;)|\&lt;br /&gt;
icon_bar (&amp;quot;sani_water_tap&amp;quot;,[vaillant:HwcHours_hoursum2_value],0,2000,120,0,&amp;quot;h&amp;quot;,0)|\&lt;br /&gt;
icon_bar (&amp;quot;sani_floor_heating_neutral&amp;quot;,[Heizenergie:Vortag_hc],0,150,120,0,&amp;quot;kWh&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_bar_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
==== Anzeige eines Werteverlaufs und des aktuellen Wertes mit Hilfe der SVG-Funktion &#039;&#039;&#039;card&#039;&#039;&#039; ====&lt;br /&gt;
Es wird der aktuelle Wert eines Readings, sein zeitlicher Verlauf sowie der maximale und minimale Wert in Form einer Informationskarte visualisiert. Das Erscheinungsbild kann über zahlreiche Parameter individualisiert werden. Die Besonderheit ist das Argument &#039;&#039;&#039;col&amp;lt;Anzahl&amp;gt;&amp;lt;Zeitformat&amp;gt;&#039;&#039;&#039; bei der Angabe des Readings der Form &#039;&#039;&#039;[&amp;lt;Device&amp;gt;:&amp;lt;Reading&amp;gt;:col&amp;lt;Anzahl&amp;gt;&amp;lt;Zeitformat&amp;gt;]&#039;&#039;&#039;. Dadurch werden Daten des Readings temporär im DOIF-Modul gesammelt und für die Erzeugung eines Graphen zur Verfügung gestellt - es sind keine weiteren Definitionen erforderlich. Dabei wird besonders sparsam mit der Datensammlung umgegangen, es werden maximal 72 Werte (in Timeslots)  gespeichert, unabhängig davon wie lange die Zeitspanne ist und wie oft die Daten ankommen. Die Auflösung des Graphen nimmt mit der Zeitspanne ab - es werden immer maximal 72 Werte dargestellt. Daraus ergibt sich bei einer Stunde eine Auflösung von 3600/72 = 50 Sekunden/Eintrag, bei 6 Stunden sind es 6*60/72 = 5 Minuten/Eintrag, für eine Woche 7*24*60/72 = 140 Minuten/Eintrag usw. Die gesammelten Daten werden über den FHEM-Befehl &#039;&#039;&#039;save&#039;&#039;&#039; in versteckten Readings des jeweiligen DOIF-Moduls gespeichert.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;card&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
card ($collect,$header,$icon,$min,$max,$minColor,$maxColor, $unit,$colorRef,$decfont,$prop,$ringModel,$lightness, $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)&lt;br /&gt;
&lt;br /&gt;
$collect   &lt;br /&gt;
# Angabe eines Readings oder eines Arrays mit mehreren Readings der Form [&amp;lt;Device&amp;gt;:&amp;lt;Reading&amp;gt;:col&amp;lt;Anzahl&amp;gt;&amp;lt;Zeitformat&amp;gt;], mit Hilfe des Argumentes col (von collect) wird das Modul angewiesen Daten des Readings über einen bestimmten Zeitraum zu sammeln&lt;br /&gt;
&lt;br /&gt;
col&amp;lt;number&amp;gt;&amp;lt;timeformat&amp;gt; &lt;br /&gt;
# &amp;lt;timeformat&amp;gt;: d Tage, w Wochen, ohne Angabe des Zeitformates wird &amp;lt;Anzahl&amp;gt; in Stunden interpretiert. &lt;br /&gt;
# Beispiele: col (entspricht col24), col1, col12, col1d, col3d, col1w, col4w, col52w usw.&lt;br /&gt;
&lt;br /&gt;
$header    # &amp;quot;&amp;lt;Überschrifttext,&amp;lt;Style-SVG-Text-Attribute&amp;gt;&amp;quot;, optional&lt;br /&gt;
$icon      # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position,Rotation&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position, Rotation sind optional&lt;br /&gt;
$min       # minimaler Wert, optional, default=0&lt;br /&gt;
$max       # maximaler Wert, optional, default=100&lt;br /&gt;
$minColor  # Farbe (hue: 0-360) des kleinsten Wertes, optional, default = 0 (rot)&lt;br /&gt;
$maxColor  # Farbe (hue: 0-360) des maximalen Wertes, optional, default = 120 (grün)&lt;br /&gt;
$unit      &lt;br /&gt;
# Einheit des Wertes, optional, default = undef, falls unter $collect ein Array für mehrere Readings angegeben wurde, so werden hier als Array die entsprechenden Einheiten angegeben, zusätzlich kann kommagetrennt pro Einheit Farbe des Graphen angegeben werden&lt;br /&gt;
&lt;br /&gt;
$colorRef  &lt;br /&gt;
# Referenz auf eine Funktion, die zu einem Wert einen Farbwert (hue: 0-360) bestimmt, oder eine Referenz auf eine Arrayliste mit Grenzwerten und Farben, optional, default = undef&lt;br /&gt;
&lt;br /&gt;
$decFont&lt;br /&gt;
# &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Style-SVG-Attribute Wert&amp;gt;,&amp;lt;Style-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&lt;br /&gt;
$prop      &lt;br /&gt;
# Eigenschaft von card: &amp;quot;&amp;lt;size&amp;gt;,&amp;lt;y-scaling&amp;gt;,&amp;lt;steps&amp;gt;,&amp;lt;noFooter&amp;gt;,&amp;lt;noColor&amp;gt;,&amp;lt;hring&amp;gt;,&amp;lt;width&amp;gt;&amp;quot;, optional&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;size&amp;gt;: Größe der der Karte, default = 130,&lt;br /&gt;
# &amp;lt;y-scaling&amp;gt;: feste Y-Skalierung: 1, sonst automatische Skalierung,&lt;br /&gt;
# &amp;lt;steps&amp;gt;: 1 für Stufen,&lt;br /&gt;
# &amp;lt;noFooter&amp;gt;: 1 für keine Fußzeile,&lt;br /&gt;
# &amp;lt;noColor&amp;gt;: 1 für graue y-Achsenbeschriftung, &lt;br /&gt;
# &amp;lt;hring&amp;gt;: 1 für Halbringdarstellung, &lt;br /&gt;
# &amp;lt;width&amp;gt;: Breite der Karte, default: 160&lt;br /&gt;
&lt;br /&gt;
$ringModel&lt;br /&gt;
# &#039;&amp;lt;color gradient&amp;gt;,&amp;lt;min/max&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;pointer&amp;gt;,&amp;lt;mode&amp;gt;&#039;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;color gradient&amp;gt;: 1 für monochrom&lt;br /&gt;
# &amp;lt;min/max&amp;gt;: Style-SVG-Attribute oder 1 zum Anzeigen der Min-/Maxwerte&lt;br /&gt;
# &amp;lt;inner ring&amp;gt;: Style-SVG-Attribute oder 1 zum Anzeigen des Innenringes&lt;br /&gt;
# &amp;lt;pointer&amp;gt;: Breite des Zeigers in Pixel&lt;br /&gt;
# &amp;lt;mode&amp;gt;: 0 Standard Min. - Max., 1 negativ - Null - positiv, 2 Null - negativ/positiv&lt;br /&gt;
# alle Parameter sind optional, default keine Angaben: &#039;,,,,,,&#039;&lt;br /&gt;
&lt;br /&gt;
$lightness &lt;br /&gt;
# Helligkeit einzelner Elemente (0-100) &amp;quot;&amp;lt;ring&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;minMax&amp;gt;,&amp;lt;unit&amp;gt;,&amp;lt;value&amp;gt;,&amp;lt;icon&amp;gt;&amp;quot;, optional, default: &amp;quot;50,50,50,40,50,40&amp;quot;&lt;br /&gt;
&lt;br /&gt;
$collect2  # optionale Angaben für ein zweites Reading (es ist hier nur eine Readingangabe erlaubt)&lt;br /&gt;
$min       # restliche Parameter&lt;br /&gt;
$max       # entsprechen der Syntax&lt;br /&gt;
...        # des ersten Sensors&lt;br /&gt;
$decfonts2 # &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird &#039;&#039;&#039;$colorRef&#039;&#039;&#039; nicht angegeben, so wird der Farbwert zwischen &#039;&#039;&#039;$minColor&#039;&#039;&#039; und &#039;&#039;&#039;$maxColor&#039;&#039;&#039; linear interpoliert&lt;br /&gt;
Werden mehrere Readings angegeben, so müssen sie alle die gleiche Zeitspanne besitzen (Zeitangabe bei col)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* Anwendungsbeispiel [[DOIF/uiTable_Schnelleinstieg#Visualisierung:_Wetterstation|Wetterstation]]&lt;br /&gt;
* Anwendungsbeispiel [[DOIF/uiTable_Schnelleinstieg#Visualisierung:_aktueller_Spritpreis|Spritpreise]]&lt;br /&gt;
* Anwendungsbeispiel [[DOIF/uiTable_Schnelleinstieg#Visualisierung_und_Steuerung:_Heiztherme|Heiztherme]]&lt;br /&gt;
* svg-Funktion [[DOIF/uiTable_Schnelleinstieg#Farbskalierte_Anzeige_eines_Icons_mit_einem_Zahlenwert_mit_Hilfe_der_universellen_SVG-Funktion_icon_ring.2Ficon_mring.2Ficon_uring|icon_ring]] &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_collect DOIF ##&lt;br /&gt;
attr di_collect uiTable {package ui_Table;;}\&lt;br /&gt;
card([Aussensensor:temperature:col12],&amp;quot;Außen&amp;quot;,&amp;quot;temp_outside&amp;quot;,-10,45,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,undef)|\&lt;br /&gt;
card([Tankstelle:Diesel:col12],&amp;quot;Sprit,fill:darkorange&amp;quot;,&amp;quot;fuel&amp;quot;,&amp;quot;1.00&amp;quot;,&amp;quot;1.40&amp;quot;,120,0,&amp;quot;Diesel €&amp;quot;,undef,&amp;quot;2&amp;quot;,&amp;quot;,,1&amp;quot;)\&lt;br /&gt;
card([zaehler:l-Produktion:col12],undef,[zaehler:l-Produktion] &amp;gt; 0 ? &amp;quot;sani_solar\@colorVal1&amp;quot;:&amp;quot;fa_bolt\@colorVal2&amp;quot;,0,3.6,30,60,&amp;quot;PV kW&amp;quot;,undef,&amp;quot;1,,font-size:50%&amp;quot;)|\&lt;br /&gt;
card([ESPEasy_Eingang_CO2:PPM:col12],undef,&amp;quot;air&amp;quot;,400,1200,120,0,&amp;quot;ppm&amp;quot;,[600,120,1000,60,1200,0],0,undef,&#039;0,1,1&#039;,&amp;quot;50,35,45,35,50,35&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:svgcard.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defmod di_cards DOIF {}&lt;br /&gt;
attr di_cards uiTable {package ui_Table;;}\&lt;br /&gt;
&amp;quot;Standard&amp;quot;|\&lt;br /&gt;
card([Aussensensor:temperature:col],undef,&amp;quot;temp_outside&amp;quot;,-10,50,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130&amp;quot;)\&lt;br /&gt;
&amp;quot;mit Halbring&amp;quot;|\&lt;br /&gt;
card([Aussensensor:temperature:col],&amp;quot;Außen&amp;quot;,&amp;quot;temp_outside&amp;quot;,-10,50,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,1&amp;quot;)\&lt;br /&gt;
&amp;quot;mit Halbring&amp;quot;,&amp;quot;ohne Fußzeile&amp;quot;,&amp;quot;Breite 110&amp;quot;|\&lt;br /&gt;
card([Aussensensor:temperature:col],&amp;quot;Außen&amp;quot;,&amp;quot;temp_outside&amp;quot;,-10,50,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130,,,1,,1,110&amp;quot;)\&lt;br /&gt;
&amp;quot;Standard&amp;quot;,&amp;quot;Breite 200&amp;quot;|\&lt;br /&gt;
card([Aussensensor:temperature:col],&amp;quot;Außen&amp;quot;,&amp;quot;temp_outside&amp;quot;,-10,50,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,200&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:di_card_variations.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition mit zwei Readings mit unterschiedlichen Einheiten&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_cards DOIF {}&lt;br /&gt;
attr di_cards uiTable {package ui_Table;;}\&lt;br /&gt;
&amp;quot;Standard&amp;quot;|\&lt;br /&gt;
card([Aussensensor:temperature:col],&amp;quot;Außen&amp;quot;,&amp;quot;temp_outside&amp;quot;,-10,60,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130,,,,&amp;quot;,undef,undef,[outsensor:humidity:col],0,100,undef,undef,&amp;quot;%&amp;quot;,\&amp;amp;hum_hue,&amp;quot;0&amp;quot;)\&lt;br /&gt;
&amp;quot;ohne Header&amp;quot;|\&lt;br /&gt;
card([Aussensensor:temperature:col],undef,&amp;quot;temp_outside&amp;quot;,-10,60,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130,,,,&amp;quot;,undef,undef,[outsensor:humidity:col],0,100,undef,undef,&amp;quot;%&amp;quot;,\&amp;amp;hum_hue,&amp;quot;0&amp;quot;)\&lt;br /&gt;
&amp;quot;ohne Header&amp;quot;,&amp;quot;ohne Fußzeile&amp;quot;|card([Aussensensor:temperature:col],undef,&amp;quot;temp_outside&amp;quot;,-10,60,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130,,,1,&amp;quot;,undef,undef,[outsensor:humidity:col],0,100,undef,undef,&amp;quot;%&amp;quot;,\&amp;amp;hum_hue,&amp;quot;0&amp;quot;)\&lt;br /&gt;
&amp;quot;Als Halbring&amp;quot;|\&lt;br /&gt;
card([Aussensensor:temperature:col],&amp;quot;Außen&amp;quot;,&amp;quot;temp_outside&amp;quot;,-10,60,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,1&amp;quot;,undef,undef,[outsensor:humidity:col],0,100,undef,undef,&amp;quot;%&amp;quot;,\&amp;amp;hum_hue,&amp;quot;0&amp;quot;)\&lt;br /&gt;
&amp;quot;ohne Fußzeile&amp;quot;|\&lt;br /&gt;
card([Aussensensor:temperature:col],&amp;quot;Außen&amp;quot;,&amp;quot;temp_outside&amp;quot;,-10,60,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130,,,1,,1&amp;quot;,undef,undef,[outsensor:humidity:col],0,100,undef,undef,&amp;quot;%&amp;quot;,\&amp;amp;hum_hue,&amp;quot;0&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:di_card_collect2.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinitionen mit mehreren Readings mit gleicher Einheit&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Sprit DOIF ##&lt;br /&gt;
attr Sprit uiTable {package ui_Table;;}\&lt;br /&gt;
card([[Tankstelle:SuperE5:col24],[Tankstelle:Diesel:col24]],&amp;quot;Sprit&amp;quot;,&amp;quot;fuel&amp;quot;,&amp;quot;1.20&amp;quot;,&amp;quot;1.60&amp;quot;,120,0,[&amp;quot;E5&amp;quot;,&amp;quot;Diesel&amp;quot;],undef,&amp;quot;2&amp;quot;,&amp;quot;,,1&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:di_Sprit2.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV DOIF {}&lt;br /&gt;
attr PV DOIF_Readings l_Eigenv: [zaehler:l-Produktion]-[zaehler:l-Lieferung],\&lt;br /&gt;
Eigenv:[zaehler:Produktion]-[zaehler:Lieferung],\&lt;br /&gt;
l_Verbrauch: [zaehler:l-Bezug,0]+[$SELF:l_Eigenv,0],\&lt;br /&gt;
Verbrauch:[zaehler:Bezug]+[$SELF:Eigenv],\&lt;br /&gt;
l_Bezug:-[zaehler:l-Bezug]&lt;br /&gt;
attr PV uiTable {\&lt;br /&gt;
 package ui_Table;;\&lt;br /&gt;
 $SHOWNOSTATE=1;;\&lt;br /&gt;
}\&lt;br /&gt;
card([[zaehler:l-Produktion:col],[$SELF:l_Eigenv:col],[$SELF:l_Bezug:col]],&amp;quot;kW&amp;quot;,&amp;quot;fa_bolt\@silver&amp;quot;,-3.6,3.6,0,90,[&amp;quot;Solar&amp;quot;,&amp;quot;Eigen.&amp;quot;,&amp;quot;Bezug&amp;quot;],[(-1,0,0,30,1,60,3.6,90)],&amp;quot;2&amp;quot;,&amp;quot;167,,1,,,1&amp;quot;,&amp;quot;,,1,6&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:di_card_energie.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition mit mehreren Readings mit einfarbigen Graphen&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_heating DOIF {}&lt;br /&gt;
attr di_heating uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
card([[ESPEasy_ESP_Temp_Vorlauf:Temperature:col],[ESPEasy_ESP_Temp_Keller_Ruecklauf:Temperature:col]],&amp;quot;Umwälzpumpe&amp;quot;,([vaillant:Pumpenstatus] eq &amp;quot;on&amp;quot; ? &amp;quot;sani_floor_heating\@Darkorange&amp;quot; : &amp;quot;sani_floor_heating_neutral\@white&amp;quot;),15,70,undef,undef,[&amp;quot;Vor. °C,red&amp;quot;,&amp;quot;Rück. °C,#287afc&amp;quot;],\&amp;amp;temp_hue,undef,&amp;quot;,,1,,1&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:di_card_pump.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
==== 3d-Balkendarstellung mehrerer Zahlenwerten mit Hilfe der universellen SVG-Funktion &#039;&#039;&#039;cylinder&#039;&#039;&#039; ====&lt;br /&gt;
Es können mehrere Zahlenwerte mit Legende farbig in Balkenform visualisiert werden. Negative Werte werden als Balken nach unten dargestellt, positive nach oben, der Nullpunkt wird automatisch berechnet.&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;cylinder&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
cylinder ($header,$min,$max,$unit,$width,$height,$size,$dec,($value1,$color1,$text1),($value2,$color2,$text2),...&lt;br /&gt;
&lt;br /&gt;
$header     # Überschrift&lt;br /&gt;
$min        # minimaler Wert, optional, default = 0&lt;br /&gt;
$max        # maximaler Wert, optional, default = 100&lt;br /&gt;
$unit       # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$width      # Breite der Grafik, optional, default = wird bei Beschriftungen automatisch angepasst&lt;br /&gt;
$height     # Höhe der Grafik, optional, default = wird automatisch berechnet&lt;br /&gt;
$size       # Größe der Grafik, optional, default = 100&lt;br /&gt;
$dec        # Anzahl der Nachkommastellen, optional, default=1&lt;br /&gt;
$value1     # erster Zahlenwert&lt;br /&gt;
$color1     # HSL-Farbe des ersten Balkens: &amp;quot;&amp;lt;hue&amp;gt;.&amp;lt;saturation&amp;gt;.&amp;lt;lightness&amp;gt;&amp;quot; (hue:0-360,saturation:0-100,lightness:0-100), saturation (default:100) und lightness (default:50) sind optional&lt;br /&gt;
$text1      # Beschriftung des Zahlenwertes in der Legende, optional, default = undef&lt;br /&gt;
$value2     # zweiter Zahlenwert, optional&lt;br /&gt;
$color2     # HSL-Farbe des zweiten Balkens: &amp;quot;&amp;lt;hue&amp;gt;.&amp;lt;saturation&amp;gt;.&amp;lt;lightness&amp;gt;&amp;quot; (hue:0-360,saturation:0-100,lightness:0-100), saturation (default:100) und lightness (default:50) sind optional&lt;br /&gt;
$text2      # Beschriftung des Zahlenwertes in der Legende, optional, default = undef&lt;br /&gt;
...&lt;br /&gt;
Es können weitere Zahlenwerte jeweils mit Farbe und Beschriftung optional angegeben werden &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_cylinder DOIF ##&lt;br /&gt;
attr di_cylinder room Test,wiki&lt;br /&gt;
attr di_cylinder uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;normal&amp;quot;|cylinder(&amp;quot;&amp;quot;,0,100,&amp;quot;%&amp;quot;,80,undef,undef,0,[Wasserzisterne:state],200,undef)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;mit Überschrift&amp;quot;|cylinder(&amp;quot;Zisterne&amp;quot;,0,100,&amp;quot;%&amp;quot;,80,undef,undef,0,[Wasserzisterne:state],200,undef)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;kleiner&amp;quot;|cylinder(&amp;quot;Zisterne&amp;quot;,0,100,&amp;quot;%&amp;quot;,80,undef,80,0,[Wasserzisterne:state],200,undef)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;hoch&amp;quot;|cylinder(&amp;quot;Zisterne&amp;quot;,0,100,&amp;quot;%&amp;quot;,undef,100,undef,0,[Wasserzisterne:state],200,undef)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;mit Beschriftung&amp;quot;|cylinder(&amp;quot;Zisterne&amp;quot;,0,100,&amp;quot;%&amp;quot;,undef,100,undef,0,[Wasserzisterne:state],200,&amp;quot;Wasserstand&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;mit mehreren Informationen&amp;quot;|cylinder(&amp;quot;Energie&amp;quot;,-20,30,&amp;quot;kWh&amp;quot;,undef,undef,undef,1,[zaehler:Bezug],0,&amp;quot;Bezug&amp;quot;,[zaehler:Produktion],60,&amp;quot;Produktion&amp;quot;,[zaehler:Eigenverbrauch],30,&amp;quot;Eigenverbrauch&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;mit hellen Farben&amp;quot;| cylinder(&amp;quot;Tag&amp;quot;,0,100,&amp;quot;kWh&amp;quot;,undef,undef,undef,1,[Heizenergie:Tagesverbrauch_hc]/100000,&amp;quot;30.100.70&amp;quot;,&amp;quot;letzter&amp;quot;,[Heizenergie:heute_hc]/100000,&amp;quot;60.100.70&amp;quot;,&amp;quot;aktuell&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:cylinder_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
==== Balkendarstellung mehrerer Zahlenwerte mit Hilfe der universellen SVG-Funktion &#039;&#039;&#039;cylinder_bars&#039;&#039;&#039; ====&lt;br /&gt;
Es können mehrere Zahlenwerte mit Legende farbig in Balkenform visualisiert werden. Negative Werte werden als Balken nach unten dargestellt, positive nach oben, der Nullpunkt wird automatisch berechnet. Die &#039;&#039;&#039;cylinder_bars&#039;&#039;&#039;-SVG-Funkton besitzt die gleichen Argumente, wie die obige &#039;&#039;&#039;cylinder&#039;&#039;&#039;-SVG-Funktion, mehrerer Balken werden jedoch nicht übereinander, sondern nebeneinander dargestellt.&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;cylinder_bars&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
cylinder_bars ($header,$min,$max,$unit,$width,$height,$size,$dec,($value1,$color1,$text1),($value2,$color2,$text2),...&lt;br /&gt;
&lt;br /&gt;
$header     # Überschrift&lt;br /&gt;
$min        # minimaler Wert, optional, default = 0&lt;br /&gt;
$max        # maximaler Wert, optional, default = 100&lt;br /&gt;
$unit       # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$width      # Breite der Grafik, optional, default = wird bei Beschriftungen automatisch angepasst&lt;br /&gt;
$height     # Höhe der Grafik, optional, default = wird automatisch berechnet&lt;br /&gt;
$size       # Größe der Grafik, optional, default = 100&lt;br /&gt;
$dec        # Anzahl der Nachkommastellen, optional, default=1&lt;br /&gt;
$value1     # erster Zahlenwert&lt;br /&gt;
$color1     # HSL-Farbe des ersten Balkens: &amp;quot;&amp;lt;hue&amp;gt;.&amp;lt;saturation&amp;gt;.&amp;lt;lightness&amp;gt;&amp;quot; (hue:0-360,saturation:0-100,lightness:0-100), saturation (default:100) und lightness (default:50) sind optional&lt;br /&gt;
$text1      # Beschriftung des Zahlenwertes in der Legende, optional, default = undef&lt;br /&gt;
$value2     # zweiter Zahlenwert, optional&lt;br /&gt;
$color2     # HSL-Farbe des zweiten Balkens: &amp;quot;&amp;lt;hue&amp;gt;.&amp;lt;saturation&amp;gt;.&amp;lt;lightness&amp;gt;&amp;quot; (hue:0-360,saturation:0-100,lightness:0-100), saturation (default:100) und lightness (default:50) sind optional&lt;br /&gt;
$text2      # Beschriftung des Zahlenwertes in der Legende, optional, default = undef&lt;br /&gt;
...&lt;br /&gt;
Es können weitere Zahlenwerte jeweils mit Farbe und Beschriftung optional angegeben werden &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_wasserverbrauch DOIF ##&lt;br /&gt;
attr di_wasserverbrauch uiTable {package ui_Table;;}\&lt;br /&gt;
cylinder_bars(&amp;quot;Monat&amp;quot;,0,15,&amp;quot;m³&amp;quot;,undef,undef,undef,1,[Wasserverbrauch:monatsdurchschnitt],30,&amp;quot;Durchschnitt&amp;quot;,[Wasserverbrauch:monatsverbrauch]/1000,220,&amp;quot;letzter&amp;quot;,[Wasserverbrauch:monat]/1000,180,&amp;quot;aktuell&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
cylinder_bars(&amp;quot;Monat&amp;quot;,0,15,&amp;quot;m³&amp;quot;,undef,undef,undef,1,[Wasserverbrauch:jan],30,&amp;quot;Januar&amp;quot;,[Wasserverbrauch:feb],220,&amp;quot;Februar&amp;quot;,[Wasserverbrauch:mrz],180,&amp;quot;März&amp;quot;,[Wasserverbrauch:apr],30,&amp;quot;April&amp;quot;,[Wasserverbrauch:mai],220,&amp;quot;Mai&amp;quot;,[Wasserverbrauch:jun],180,&amp;quot;Juni&amp;quot;,[Wasserverbrauch:jul],30,&amp;quot;Juli&amp;quot;,[Wasserverbrauch:aug],220,&amp;quot;August&amp;quot;,[Wasserverbrauch:sep],180,&amp;quot;September&amp;quot;,[Wasserverbrauch:okt],30,&amp;quot;Oktober&amp;quot;,[Wasserverbrauch:nov],220,&amp;quot;November&amp;quot;,[Wasserverbrauch:dez],180,&amp;quot;Dezember&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:cylinder_bars_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
=== Farbskalierte Temperaturanzeige mit Hilfe der Funktion &#039;&#039;&#039;temp&#039;&#039;&#039; ===&lt;br /&gt;
Die Farbe der dargestellten Temperatur ist abhängig vom Temperaturwert:&lt;br /&gt;
[[Datei:Farbskalierung temp.png|600px|ohne]]&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;temp&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
temp ($temp,$size,$icon)&lt;br /&gt;
&lt;br /&gt;
$temp # Temperatur&lt;br /&gt;
$size # Schriftgröße in Pixel (pt), optional&lt;br /&gt;
$icon # Icon, welches vorangestellt wird, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_temp DOIF ##&lt;br /&gt;
attr di_uiTable_temp uiTable {\&lt;br /&gt;
  package ui_Table;;           ## Package für uiTable-Funktionen\&lt;br /&gt;
  $TC{0..2}=&amp;quot;align=&#039;center&#039;&amp;quot;;; ## zentrierte Darstellung aller Tabellenspalten\&lt;br /&gt;
}\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Aussen&amp;quot;|&amp;quot;Bad&amp;quot;|&amp;quot;Warmwasser&amp;quot;                             ## mit | werden Tabellenzellen voneinander getrennt \&lt;br /&gt;
temp([Aussensensor:temperature])|                       ## Anzeige des Readings &#039;temperature&#039; des Gerätes &#039;Aussensensor&#039;  \&lt;br /&gt;
temp([TH_Bad_HM:measured-temp],24,&amp;quot;temp_temperature&amp;quot;)|  ## Schriftgröße 24pt, mit Icon namens temp_temperature\&lt;br /&gt;
temp([T_Warmwasserspeicher:temperature:d1],20)          ## Schriftgröße 20pt&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:Temp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
=== Farbskalierte Feuchtigkeitsanzeige mit Hilfe der Funktion &#039;&#039;&#039;hum&#039;&#039;&#039; ===&lt;br /&gt;
Die Farbe der dargestellten Feuchtigkeit ist abhängig vom Feuchtigkeitswert:&lt;br /&gt;
[[Datei:Farbskalierung hum.png|350px|ohne]]&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;hum&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
hum ($hum,$size,$icon)&lt;br /&gt;
&lt;br /&gt;
$hum  # Feuchtigkeit&lt;br /&gt;
$size # Schriftgröße in Pixel (pt), optional&lt;br /&gt;
$icon # Icon, welches vorangestellt wird, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_hum DOIF ##&lt;br /&gt;
attr di_uiTable_hum uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
$TC{1}=&amp;quot;align=&#039;center&#039;&amp;quot;;; ## zweite Spalte der Tabelle zentriert\&lt;br /&gt;
}\&lt;br /&gt;
## Tabellendefinition \&lt;br /&gt;
\&lt;br /&gt;
## Anzeige des Readings &#039;humidity&#039; des Thermostats &#039;TH_Bad_HM&#039;  \&lt;br /&gt;
&amp;quot;Bad&amp;quot;|hum ([TH_Bad_HM:humidity])\&lt;br /&gt;
\&lt;br /&gt;
## Feuchtigkeit in Größe 10pt mit Temperatur in einer Tabellenzelle\&lt;br /&gt;
&amp;quot;Aussen&amp;quot;|temp ([Aussensensor:temperature]),hum ([Aussensensor:humidity],10)\&lt;br /&gt;
\&lt;br /&gt;
## Feuchtigkeit in Größe 26pt mit Icon namens &#039;temperature_humidity&#039;\&lt;br /&gt;
&amp;quot;Keller&amp;quot;|hum ([TH_Keller_HM:humidity],26,&amp;quot;temperature_humidity&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable Funktion hum.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
=== Textformatierungen mit Hilfe der Funktion &#039;&#039;&#039;style&#039;&#039;&#039; ===&lt;br /&gt;
Texte werden in Farbe, Größe und Schriftart statisch oder dynamisch formatiert.&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;style&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
style ($text,$color,$font_size,$font_weight)&lt;br /&gt;
&lt;br /&gt;
$text        # anzuzeigender Text&lt;br /&gt;
$color       # CSS color, optional&lt;br /&gt;
$font_size   # Schriftgröße in Pixel (pt), optional&lt;br /&gt;
$font_weight # CSS Schriftart, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Mögliche Werte für &#039;&#039;&#039;&#039;&#039;color&#039;&#039;&#039;&#039;&#039; und &#039;&#039;&#039;&#039;&#039;font_weight&#039;&#039;&#039;&#039;&#039; können in einschlägiger Dokumentation zu CSS nachgeschlagen werden&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_style DOIF ##&lt;br /&gt;
attr di_uiTable_style uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
## statische Farbgebung, Größe, Schriftart \&lt;br /&gt;
style(&amp;quot;Montag&amp;quot;,&amp;quot;orange&amp;quot;)\&lt;br /&gt;
style(&amp;quot;Dienstag&amp;quot;,&amp;quot;red&amp;quot;,14)\&lt;br /&gt;
style(&amp;quot;Mittwoch&amp;quot;,&amp;quot;#00FFFF&amp;quot;,20)\&lt;br /&gt;
style(&amp;quot;Donnerstag&amp;quot;,&amp;quot;blue&amp;quot;,23,&amp;quot;bold&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## dynamische Farbgebung abhängig vom Zustand des Gerätes &#039;Alarm&#039;\&lt;br /&gt;
style(&amp;quot;Alarm&amp;quot;,([Alarm:state] eq &amp;quot;on&amp;quot; ? &amp;quot;red&amp;quot;:&amp;quot;green&amp;quot;))\&lt;br /&gt;
\&lt;br /&gt;
## dynamische Farbgebung des Zustands des Gerätes &#039;Alarm&#039;\&lt;br /&gt;
style([Alarm:state],([Alarm:state] eq &amp;quot;on&amp;quot; ? &amp;quot;red&amp;quot;:&amp;quot;green&amp;quot;))\&lt;br /&gt;
\&lt;br /&gt;
## variabler Text abhängig vom Zustand des Gerätes &#039;Alarm&#039;\&lt;br /&gt;
style(([Alarm:state] eq &amp;quot;on&amp;quot; ? &amp;quot;Alarm aktiv&amp;quot;:&amp;quot;Alarm deaktiviert&amp;quot;),&amp;quot;red&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:Style.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
=== Icon-Darstellung mit Hilfe der Funktion &#039;&#039;&#039;ICON&#039;&#039;&#039; ===&lt;br /&gt;
Mit Hilfe der Funktion &#039;&#039;&#039;ICON&#039;&#039;&#039; kann ein FHEM-Icon dargestellt werden&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;ICON&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
ICON ($icon)&lt;br /&gt;
&lt;br /&gt;
$icon        # Icon mit Farbgebung&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ICON&#039;&#039;&#039; benutzt die Funktion [[DevelopmentFHEMWEB-API#FW_makeImage|FW_makeImage]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* [[DOIF/uiTable Schnelleinstieg#hsv-Funktion für Farbskalierungen|hsv-Funktion]]&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_Table_ICON DOIF ##&lt;br /&gt;
attr di_Table_ICON uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
ICON(&amp;quot;temp_frost&amp;quot;) |  ## Icon ohne Einfärbung\&lt;br /&gt;
ICON(&amp;quot;temp_frost\@blue&amp;quot;) | ## Icon in CSS-Farbe blau\&lt;br /&gt;
ICON(&amp;quot;temp_frost\@#8A2BE2&amp;quot;) | ## Icon in CSS-Farbe #8A2BE2\&lt;br /&gt;
ICON(&amp;quot;temp_frost\@&amp;quot;.([Aussensensor:temperature] &amp;gt; 0 ? &amp;quot;orange&amp;quot;:&amp;quot;blue&amp;quot;))| ## Icon in CSS-Farbe orange über Null Grad, sonst in CSS-Farbe blau\&lt;br /&gt;
ICON(&amp;quot;temp_frost\@&amp;quot;.hsv ([Aussensensor:temperature],-20,40,320,0)) ## Icon in Farbskalierung von violett (-20 °C) bis rot (40 °C) mit Hilfe der Funktion hsv&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable_IC.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
=== Icon-Darstellung mit Text mit Hilfe der Funktion &#039;&#039;&#039;icon_label&#039;&#039;&#039; ===&lt;br /&gt;
Mit Hilfe der Funktion &#039;&#039;&#039;icon_label&#039;&#039;&#039; kann ein FHEM-Icon mit einem angehängten Text/Wert dargestellt werden.&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;icon_label&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_label ($icon,$text,$color,$color_bg,$pos_left,$pos_top)&lt;br /&gt;
$icon        # FHEM-Icon mit Farboption&lt;br /&gt;
$text        # dargestellter Text&lt;br /&gt;
$color       # Farbe des Textes, optional&lt;br /&gt;
$color       # Hintergrundfarbe des Textes, optional&lt;br /&gt;
$pos_left    # horizontale Position des Textes in px, default -5, optional&lt;br /&gt;
$pos_top     # vertikale Position des Textes in px, default -8, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Anwendungsbeispiele&#039;&#039;&#039;&lt;br /&gt;
* [[DOIF/uiTable Schnelleinstieg#Anzahl der Tage bis zur Abfall-Entsorgung|Abfall]]&lt;br /&gt;
* [[DOIF/uiTable Schnelleinstieg#Visualisierung: aktueller Spritpreis|Sprit]]&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_icon_label DOIF ##&lt;br /&gt;
attr di_uiTable_icon_label uiTable { package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
icon_label(&amp;quot;fuel&amp;quot;,[Tankstelle:Diesel])|\&lt;br /&gt;
icon_label(&amp;quot;fuel&amp;quot;,[Tankstelle:Diesel],&amp;quot;red&amp;quot;)|\&lt;br /&gt;
icon_label(&amp;quot;fuel\@blue&amp;quot;,[Tankstelle:Diesel],&amp;quot;blue&amp;quot;,&amp;quot;#999999&amp;quot;)|\&lt;br /&gt;
icon_label(&amp;quot;fuel\@red&amp;quot;,[Tankstelle:Diesel],&amp;quot;red&amp;quot;,&amp;quot;white&amp;quot;,-10)|\&lt;br /&gt;
icon_label(&amp;quot;fuel&amp;quot;,[Tankstelle:Diesel],&amp;quot;white&amp;quot;,&amp;quot;red&amp;quot;,-5,8)\&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable_icon_label.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
=== Visualisierung eines Gerätes mit Hilfe der Funktion &#039;&#039;&#039;icon&#039;&#039;&#039; ===&lt;br /&gt;
Der Zustand eines Gerätes/Readings wird mit Hilfe eines Icons dargestellt.&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;icon&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon ($value,$icon_off,$icon_on,$state_off,$state_on)&lt;br /&gt;
&lt;br /&gt;
$value       # Wert &lt;br /&gt;
$icon_off    # Icon für den Wert off, default &amp;quot;off&amp;quot;&lt;br /&gt;
$icon_on     # Icon für den Wert on, default Icon für Wert &#039;off&#039; in Farbe &#039;DarkOrange&#039;, sonst Icon &#039;on&#039;, wenn $icon_off nicht definiert ist&lt;br /&gt;
$state_off   # Wert zugehörig zum Icon off, default &amp;quot;off&amp;quot;&lt;br /&gt;
$state_on    # Wert zugehörig zum Icon on, default &amp;quot;on&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_icon DOIF ##&lt;br /&gt;
attr di_uiTable_icon uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
 ## Standard-Icon off/on für Standardwert off/on \&lt;br /&gt;
&amp;quot;Lampe&amp;quot;|icon([Lampe:state])    ## entspricht icon([Lampe:state],&amp;quot;off&amp;quot;,&amp;quot;on&amp;quot;,&amp;quot;off&amp;quot;,&amp;quot;on&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Icon für Zustand &#039;off&#039; ist &#039;hue_room_hallway&#039;, für Zustand &#039;on&#039; &#039;hue_room_hallway\@DarkOrange&#039;\&lt;br /&gt;
&amp;quot;Flur&amp;quot;|icon([Lampeflur:state],&amp;quot;hue_room_hallway&amp;quot;)    ## entspricht icon([Lampeflur:state],&amp;quot;hue_room_hallway&amp;quot;,&amp;quot;hue_room_hallway\DarkOrange&amp;quot;,&amp;quot;off&amp;quot;,&amp;quot;on&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Icon für Zustand &#039;off&#039; ist &#039;status_away_2&#039;, für Zustand &#039;on&#039; &#039;status_available\@DarkOrange&#039;\&lt;br /&gt;
&amp;quot;Anwesenheit&amp;quot;|icon([Anwesenheit:state],&amp;quot;status_away_2&amp;quot;,&amp;quot;status_available\@DarkOrange&amp;quot;) \&lt;br /&gt;
\&lt;br /&gt;
## Icon für Zustand &#039;closed&#039; ist &amp;quot;status_locked&amp;quot;, für Zustand &#039;open&#039; &#039;status_open\@DarkOrange&#039;\&lt;br /&gt;
&amp;quot;Haus&amp;quot;|icon([Schloss:state],&amp;quot;status_locked&amp;quot;,&amp;quot;status_open\@DarkOrange&amp;quot;,&amp;quot;closed&amp;quot;,&amp;quot;open&amp;quot;) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable icon.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
=== Schaltbares Icon mit Hilfe der Funktion &#039;&#039;&#039;switch&#039;&#039;&#039; ===&lt;br /&gt;
Der Zustand eines Gerätes/Readings wird mit Hilfe eines Icons dargestellt, er kann über die WEB-Oberfläche durch Anklicken geschaltet werden. Damit der Zustand des Gerätes geschaltet werden kann, muss das Gerät den set-Befehl unterstützen.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;switch&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
switch ($value,$icon_off,$icon_on,$state_off,$state_on)&lt;br /&gt;
&lt;br /&gt;
$value       # [&amp;lt;device&amp;gt;:&amp;lt;reading&amp;gt;] &lt;br /&gt;
$icon_off    # Icon für den Wert off, default &amp;quot;off&amp;quot;&lt;br /&gt;
$icon_on     # Icon für den Wert on, default Icon für Wert &#039;off&#039; in Farbe &#039;DarkOrange&#039;, sonst Icon &#039;on&#039;, wenn $icon_off nicht definiert ist&lt;br /&gt;
$state_off   # Wert zugehörig zum Icon off, default &amp;quot;off&amp;quot;&lt;br /&gt;
$state_on    # Wert zugehörig zum Icon on, default &amp;quot;on&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_switch DOIF ##&lt;br /&gt;
attr di_uiTable_switch uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
## schaltbares Icons in der Webansicht \&lt;br /&gt;
switch([Lampe:state]) | \&lt;br /&gt;
switch([Lampeflur:state],&amp;quot;hue_room_hallway&amp;quot;) |\&lt;br /&gt;
switch([Anwesenheit:state],&amp;quot;status_away_2&amp;quot;,&amp;quot;status_available\@DarkOrange&amp;quot;)|\&lt;br /&gt;
switch([Haus:state],&amp;quot;status_locked&amp;quot;,&amp;quot;status_open\@DarkOrange&amp;quot;,&amp;quot;closed&amp;quot;,&amp;quot;open&amp;quot;)\&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable switch.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
=== Rollladen: Visualisierung und Steuerung mit Hilfe der Funktion &#039;&#039;&#039;shutter&#039;&#039;&#039; ===&lt;br /&gt;
Die aktuelle Position des Rollladens (0 % - 100 %) wird über Icons visualisiert. Das Anklicken eines Symbols steuert den Rollladen auf die entsprechende Position. Prozentwerte zwischen zwei Icon-Werten werden dem nächsthöheren Icon-Wert zugeordnet.&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;shutter&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
shutter ($value,$color,$type)&lt;br /&gt;
&lt;br /&gt;
$value       # [&amp;lt;device&amp;gt;:&amp;lt;reading&amp;gt;] &lt;br /&gt;
$color       # Farbe der aktuellen Rollladenposition, vorangestelltes @ verändert die Farbe des Icons, ohne @ wird der Hintergrund des Icons eingefärbt, default ist @DarkOrange&lt;br /&gt;
$type        # optional, Anzahl der Symbole 2 bis 6, 3 ist default&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[DOIF/uiTable Schnelleinstieg#Visualisierung und Steuerung von Rollläden|Anwendungsbeispiel]]&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod ui_Table_shutter DOIF ##&lt;br /&gt;
attr ui_Table_shutter uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
shutter([R_Keller:pct],&amp;quot;\@yellow&amp;quot;,2)     ## zwei Symbole für 0 % und 100 %\&lt;br /&gt;
shutter([R_Wohnzimmer_S:pct])            ## entspricht shutter ([R_Wohnzimmer_S:pct],&amp;quot;\@DarkOrange&amp;quot;,3) \&lt;br /&gt;
shutter([R_Wohnzimmer_W1:pct],&amp;quot;blue&amp;quot;,4)  ## vier Symbole \&lt;br /&gt;
shutter([R_Wohnzimmer_W2:pct],&amp;quot;\@red&amp;quot;,5) ## fünf Symbole\&lt;br /&gt;
shutter([R_Wohnzimmer_W3:pct],&amp;quot;red&amp;quot;,6    ## sechs Symbole)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable shutter.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
===  Helligkeit: Visualisierung und Steuerung mit Hilfe der Funktion &#039;&#039;&#039;dimmer&#039;&#039;&#039; ===&lt;br /&gt;
Die aktuelle Helligkeit (0 % - 100 %) wird über Icons visualisiert. Das Anklicken eines Icons bestimmt die Helligkeit der Leuchte. Prozentwerte zwischen zwei Icon-Werten werden dem nächsthöheren Icon-Wert zugeordnet.&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;dimmer&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
dimmer ($value,$color,$type)&lt;br /&gt;
&lt;br /&gt;
$value       # [&amp;lt;device&amp;gt;:&amp;lt;reading&amp;gt;] &lt;br /&gt;
$color       # Farbe der aktuellen Helligkeit, vorangestelltes @ verändert die Farbe des Icons, ohne @ wird der Hintergrund des Icons eingefärbt, default ist @DarkOrange&lt;br /&gt;
$type        # Anzahl der Symbole 2 bis 7, 3 ist default&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_dimmer DOIF ##&lt;br /&gt;
attr di_uiTable_dimmer uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
dimmer([Strauch3:pct],&amp;quot;\@yellow&amp;quot;,2)\&lt;br /&gt;
dimmer([Strauch3:pct]) ## entspricht dimmer([Strauch3:pct],&amp;quot;\@DarkOrange&amp;quot;,3) \&lt;br /&gt;
dimmer([Strauch3:pct],&amp;quot;blue&amp;quot;,4)\&lt;br /&gt;
dimmer([Strauch3:pct],&amp;quot;\@red&amp;quot;,5)\&lt;br /&gt;
dimmer([Strauch3:pct],&amp;quot;red&amp;quot;,6)\&lt;br /&gt;
dimmer([Strauch3:pct],&amp;quot;DarkOrange&amp;quot;,7)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable dimmer.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
===  Vorgabetemperatur eines Thermostats mit Hilfe der Funktion &#039;&#039;&#039;temp_knob&#039;&#039;&#039; ===&lt;br /&gt;
Die aktuelle Vorgabetemperatur eines Thermostats wird über ein Icons visualisiert. Durch Anklicken des Ringes wird die Vorgabetemperatur verändert.&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;temp_knob&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
temp_knob ($value,$color,$set)&lt;br /&gt;
&lt;br /&gt;
$value       # [&amp;lt;device&amp;gt;:&amp;lt;reading&amp;gt;] &lt;br /&gt;
$color       # Farbe der voreingestellten Temperatur, default &amp;quot;Darkorange&amp;quot;&lt;br /&gt;
$set         # set-Befehl, default &amp;quot;set&amp;quot;, sonst muss &amp;quot;set &amp;lt;Readingname&amp;gt;&amp;quot; angegeben werden, falls sich das Reading vom set-Befehl vom angezeigten Reading unterscheidet, wie beim THRESHOLD-Modul&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod ui_Table_temp_knob DOIF ##&lt;br /&gt;
attr ui_Table_temp_knob uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
## HM-EU-Thermostat, angezeigt wird das Reading &amp;quot;desired-temp&amp;quot;, geschaltet wird über &amp;quot;set desired-temp&amp;quot; \&lt;br /&gt;
&amp;quot;Dachgeschoss&amp;quot;|temp_knob([TH_DG_HM:desired-temp]) ## entspricht temp_knob([TH_DG_HM:desired-temp],&amp;quot;Darkorange&amp;quot;,&amp;quot;set&amp;quot;) \&lt;br /&gt;
\&lt;br /&gt;
## HM-EU-Thermostat Temperaturanzeige in gelb \ &lt;br /&gt;
&amp;quot;Wohnzimmer&amp;quot;|temp_knob([TH_WZ_HM:desired-temp],&amp;quot;yellow&amp;quot;) \&lt;br /&gt;
\&lt;br /&gt;
## Beim THRESHOLD-Modul wird das Reading &amp;quot;desired_value&amp;quot; angezeigt, geändert wird die Temperatur per &amp;quot;set desired&amp;quot; \&lt;br /&gt;
&amp;quot;Küche&amp;quot;|temp_knob([TH_Kueche:desired_value],&amp;quot;red&amp;quot;,&amp;quot;set desired&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable temp knob.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
==  uiTable-&#039;&#039;&#039;Templates&#039;&#039;&#039; ==&lt;br /&gt;
Die Definition einer oder mehrere Zellen kann zu einem Template zusammengefasst werden. Durch die Nutzung von Templates kann die Definition einer Tabelle erheblich vereinfacht werden. Insb. bei gleichartigen Zellen/Zeilen für verschiedene Geräte/Readings braucht eine aufwendige Definition nicht immer wieder wiederholt werden, sondern kann jeweils mit dem Aufruf eines zuvor definierten Templates realisiert werden.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;Templates&#039;&#039;&#039;&lt;br /&gt;
* Die Definition von Templates muss vor der Tabellendefinition vorgenommen werden&lt;br /&gt;
* Eine Template-Definition beginnt mit dem Schlüsselwort &#039;&#039;&#039;DEF&#039;&#039;&#039;&lt;br /&gt;
* Der Template-Name muss mit &#039;&#039;&#039;TPL_&#039;&#039;&#039; beginnen&lt;br /&gt;
* &#039;&#039;&#039;Template-Definition&#039;&#039;&#039;-Syntax&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
DEF TPL_&amp;lt;Template-Name&amp;gt;(&amp;lt;Zellendefinition mit Platzhaltern: $1,$2,...&amp;gt;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* Templates-Definitionen können in externe Dateien ausgelagert werden&lt;br /&gt;
* Templates-Definitionen können per IMPORT-Befehl aus externen Dateien importiert werden&lt;br /&gt;
* &#039;&#039;&#039;Template-Import&#039;&#039;&#039;-Syntax&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
IMPORT &amp;lt;Pfad mit Dateinamen&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* Innerhalb einer Tabellendefinition können zuvor definierte oder importierte Templates mehrfach genutzt werden&lt;br /&gt;
* &#039;&#039;&#039;Template-Aufruf&#039;&#039;&#039;-Syntax&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
TPL_&amp;lt;Template-Name&amp;gt;(&amp;lt;Übergabeparameter für $1&amp;gt;,&amp;lt;Übergabeparameter für $2&amp;gt;,...)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod ui_Table_Template DOIF ##&lt;br /&gt;
attr ui_Table_Template uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
  $TC{1..3}=&amp;quot;align=&#039;center&#039;&amp;quot;;; ## Spalten 1 bis 3 werden zentriert\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
## Template-Definitionen beginnen vor der Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
## Das Template TPL_raum stellt eine Tabellenzeile dar, die mit Hilfe von uiTable-Funktionen mehrere Tabellenzellen definiert\&lt;br /&gt;
DEF TPL_raum (&amp;quot;$1&amp;quot; | temp([TH_$2_HM:measured-temp]),hum([TH_$2_HM:humidity]) | switch([H_$2:state],&amp;quot;fa_off&amp;quot;) | temp_knob([TH_$2_HM:desired-temp]))\&lt;br /&gt;
\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
## pro Tabellenzeile wird ein Raum mit Hilfe des oben definierten Templates &amp;quot;TPL_raum&amp;quot; dargestellt\&lt;br /&gt;
&amp;quot;Raum&amp;quot;|&amp;quot;Temp./Feuchte&amp;quot;|&amp;quot;Ventil&amp;quot;|&amp;quot;Vorgabetemp.&amp;quot;\&lt;br /&gt;
TPL_raum (Dachgeschoss,DG)  ## der Übergabeparameter &amp;quot;Dachgeschoss&amp;quot; wird im Template &amp;quot;TPL_raum&amp;quot; anstelle von $1 eingesetzt, &amp;quot;DG&amp;quot; wird anstelle von $2 eingesetzt\&lt;br /&gt;
TPL_raum (Bad,Bad)\&lt;br /&gt;
TPL_raum (Kinderzimmer ost,Kz_o)\&lt;br /&gt;
TPL_raum (Kinderzimmer west,Kz_w)\&lt;br /&gt;
TPL_raum (Wohnzimmer,WZ)\&lt;br /&gt;
TPL_raum (Keller,Keller)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable Templates.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
==  Eigene uiTable-Funktionen programmieren ==&lt;br /&gt;
Für die eigenen Bedürfnisse können eigene uiTable-Funktionen programmiert werden. In der Datei [https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DOIF/uiTable.tpl contrib/DOIF/uiTable.tpl] befinden sich alle intern definierten uiTable-Funktion aus dem package ui_Table als Kopie. Diese Funktionen können als Inspiration für eigene Entwicklung dienen. &lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;uiTable-Funktionen&#039;&#039;&#039;&lt;br /&gt;
* Es gibt drei Arten von uiTable-Funktionen, sie werden intern anhand der Rückgabewerte unterschieden&lt;br /&gt;
* uiTable-Funktionen vom Typ 1: &#039;&#039;&#039;HTML&#039;&#039;&#039;, ein Rückgabewert&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
return(&amp;lt;HTML-code&amp;gt;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* uiTable-Funktionen vom Typ 2: &#039;&#039;&#039;Style&#039;&#039;&#039; (entspricht der &#039;&#039;&#039;STY&#039;&#039;&#039;-Funktion), zwei Rückgabewerte&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
return(&amp;lt;value&amp;gt;,&amp;lt;CSS-style&amp;gt;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* uiTable-Funktionen vom Typ 3: &#039;&#039;&#039;Widget&#039;&#039;&#039; (entspricht der &#039;&#039;&#039;WID&#039;&#039;&#039;-Funktion), vier Rückgabewerte&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
return (&amp;lt;value&amp;gt;,&amp;lt;&amp;gt;,&amp;lt;FHEM-widget&amp;gt;,&amp;lt;set-command: &amp;quot;&amp;quot; or &amp;quot;set&amp;quot; or &amp;quot;set &amp;lt;Readingname&amp;gt;&amp;quot;&amp;gt;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* uiTable-Funktionen sind reine Perlfunktionen&lt;br /&gt;
* uiTable-Funktionen sollten im eigenen Package definiert werden, sonst könnten bestehende Perlfunktionen im System überschrieben werden&lt;br /&gt;
* uiTable-Funktionen können in Template-Dateien ausgelagert werden und über IMPORT-Befehl importiert werden, siehe Templates&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_function DOIF ##&lt;br /&gt;
attr di_uiTable_function uiTable {\&lt;br /&gt;
package my_uiTable;; ## eigenes Package mit selbstdefinierten Funktionen\&lt;br /&gt;
\&lt;br /&gt;
## uiTable-Funktion vom Typ &amp;quot;HTML&amp;quot;, Rückgabewert: (HTML-code)\&lt;br /&gt;
\&lt;br /&gt;
sub clock { ## Anzeige aktueller Uhrzeit mit Datum\&lt;br /&gt;
            ## Voraussetzung: contrib/DOIF/doifclock.js muss ins www/pgm2-Verzeichnis kopiert werden\&lt;br /&gt;
            ## Attribut setzen in der Webinstanz: attr &amp;lt;WEB-Instanz&amp;gt; JavaScripts pgm2/doifclock.js \&lt;br /&gt;
  my ($color,$size)=@_;;\&lt;br /&gt;
  $color=&amp;quot;darkorange&amp;quot; if (!defined ($color));; ## $color ist optional, default Darkorange\&lt;br /&gt;
  $size=&amp;quot;20&amp;quot; if (!defined ($size));;           ## $size ist optional, default 20pt\&lt;br /&gt;
  return(&amp;quot;&amp;lt;div class=&#039;doifclock&#039;style=&#039;font-weight:bold;;font-size:&amp;quot;.$size.&amp;quot;pt;;color:&amp;quot;.$color.&amp;quot;;;&#039;&amp;gt;error&amp;lt;/div&amp;gt;&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
## uiTable-Funktion vom Typ Style, Rückgabewerte (Wert,CSS-style)\&lt;br /&gt;
\&lt;br /&gt;
sub red_green { ## Farbige Skalierung von Zahlen mit Hilfe der DOIF_hsv-Funktion: von 0 - rot bis 10 - grün\&lt;br /&gt;
    my ($value)=@_;;\&lt;br /&gt;
    return ($value.&amp;quot; KW&amp;quot;,                                                   ## Wert/Text\&lt;br /&gt;
           &amp;quot;font-weight:bold;;color:&amp;quot;.::DOIF_hsv ($value,0,10,0,120,70,100) ## CSS-Style\&lt;br /&gt;
           );;\&lt;br /&gt;
} \&lt;br /&gt;
\&lt;br /&gt;
## uiTable-Funktion vom Typ Widget, Rückgabewerte (Wert,Leer,FHEM-Widget,set-Befehl)\&lt;br /&gt;
\&lt;br /&gt;
sub slider { ## FHEM-Widget Slider, weitere FHEM-Widgets siehe: https://wiki.fhem.de/wiki/FHEMWEB/Widgets\&lt;br /&gt;
    my ($value,$set)=@_;;\&lt;br /&gt;
    $set=&amp;quot;&amp;quot; if (!defined $set);;\&lt;br /&gt;
    return ($value,                   ## Zahlenwert\&lt;br /&gt;
            &amp;quot;&amp;quot;,                       ## leer\&lt;br /&gt;
            &amp;quot;slider,0,0.5,100,1&amp;quot;,     ## FHEM-Widget\&lt;br /&gt;
            $set                      ## set-Befehl des FHEM-Widgets\&lt;br /&gt;
            ) \&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Uhrzeit/Datum&amp;quot;\&lt;br /&gt;
clock(&amp;quot;yellow&amp;quot;,30)          ## obige Funktion clock\&lt;br /&gt;
&amp;quot;Dimmer&amp;quot;\&lt;br /&gt;
slider([Wohnzimmer:pct])    ## obige Funktion slider\&lt;br /&gt;
&amp;quot;Leistung&amp;quot;\&lt;br /&gt;
red_green([Leistung:state]) ## obige Funktion red_green&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable-functions.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
== Package-Konzept, Auslagerung eigener Funktionen, der &#039;&#039;&#039;IMPORT&#039;&#039;&#039;-Befehl==&lt;br /&gt;
uiTable arbeitet mit Packages. In einem Package sind definierte Funktionen gekapselt, sie kollidieren nicht mit bereits definierten Funktionen in FHEM.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;Package&#039;&#039;&#039;&lt;br /&gt;
* das für die Definition der Tabelle gültige Package wird im Perlblock des uiTable-Attributes angegeben&lt;br /&gt;
* interne uiTable-Funktionen befinden sich im Package &#039;&#039;&#039;ui_Table&#039;&#039;&#039;&lt;br /&gt;
* ohne eine Angabe eines Package befindet man sich im Package &#039;&#039;&#039;main&#039;&#039;&#039;&lt;br /&gt;
* Funktionen außerhalb des gültigen Package müssen mit &amp;lt;package-Name&amp;gt;::&amp;lt;Funktion&amp;gt; angegeben werden&lt;br /&gt;
* externe uiTable-Funktionen können per IMPORT-Befehl importiert werden&lt;br /&gt;
}} &lt;br /&gt;
=== Tabellendefinition im Package main ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod beispiel1 DOIF ##&lt;br /&gt;
attr beispiel1 uiTable ## keine Package-Definition im Perlblock\&lt;br /&gt;
\&lt;br /&gt;
## Tabellendefinition befindet sich im Package main\&lt;br /&gt;
\&lt;br /&gt;
## Funktionen aus dem main-Package können unmittelbar angegeben werden\&lt;br /&gt;
FW_makeImage(&amp;quot;scene_day&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Funktionen aus dem ui_Table-Package müssen mit vorangestelltem Package angegeben werden\&lt;br /&gt;
ui_Table::temp ([Aussensensor:tempaerature])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Tabellendefinition im Package ui_Table ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod beispiel2 DOIF ##&lt;br /&gt;
attr beispiel2 uiTable {\&lt;br /&gt;
  package ui_Table; ## Package-Angabe im Perlblock\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
## Tabellendefinition befindet sich im Package ui_Table\&lt;br /&gt;
\&lt;br /&gt;
## Funktionen aus dem main-Package müssen mit vorangestelltem package angegeben werden, der Name main kann weggelassen werden\&lt;br /&gt;
::FW_makeImage(&amp;quot;scene_day&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Funktionen aus dem ui_Table-Package können direkt angegeben werden\&lt;br /&gt;
temp ([Aussensensor:temperature])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Eigene uiTable-Funktionen im eigenen Package ===&lt;br /&gt;
Diese Art der Definition bietet sich dann an, wenn man eine eigene uiTable-Funktion nur in einem DOIF nutzen möchte.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod beispiel3 DOIF ##&lt;br /&gt;
attr beispiel3 uiTable {\&lt;br /&gt;
  package $SELF;;  ## Package-Name ist der Name des DOIF-Moduls, dadurch ist der Package-Name eindeutig\&lt;br /&gt;
  sub scene_day {  ## eigene Funktion befindet sich im eigenen Package beispiel3\&lt;br /&gt;
    return (::FW_makeImage(&amp;quot;scene_day&amp;quot;));;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
## Tabellendefinition befindet sich im Package beispiel3\&lt;br /&gt;
\&lt;br /&gt;
## Funktionen aus dem main-Package müssen mit vorangestelltem Package angegeben werden (der Name main kann weggelassen werden)\&lt;br /&gt;
::FW_makeImage(&amp;quot;scene_day&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## interne Funktionen aus dem ui_Table-Package müssen mit vorangestelltem Package ui_Table angegeben werden\&lt;br /&gt;
ui_Table::temp ([Aussensensor:temperature])\&lt;br /&gt;
\&lt;br /&gt;
## eigene Funktionen können direkt angegeben werden\&lt;br /&gt;
scene_day()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Eigene ausgelagerte uiTable-Funktionen ===&lt;br /&gt;
Möchte man das ui_Table-Package um eigene Funktionen erweitern, die man in verschiedenen DOIFs nutzen möchte, so sollte man diese in eine eigene Datei auslagern, die man mit dem IMPORT-Befehl vor der Definition der Tabelle importieren kann.&lt;br /&gt;
&lt;br /&gt;
Ausgelagerte Funktion in einer eigenen Datei z. B. my_uiTable.tpl:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
{ ## Inhalt der Datei my_uiTable.tpl&lt;br /&gt;
  package ui_Table; ## das aktuelle Package  ist ui_Table&lt;br /&gt;
  sub scene_day {   ## eigene Funktion wird zum Package ui_Table hinzugefügt &lt;br /&gt;
    return (::FW_makeImage(&amp;quot;scene_day&amp;quot;));&lt;br /&gt;
  }&lt;br /&gt;
  ## die Datei kann alle Funktionen beinhalten, die man in diversen DOIFs nutzen möchte&lt;br /&gt;
}&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 beispiel4 DOIF ##&lt;br /&gt;
attr beispiel4 uiTable ##\&lt;br /&gt;
\&lt;br /&gt;
IMPORT ./contrib/DOIF/my_uiTable.tpl ## nach dem Import befindet man sich in Package ui_Table erweitert um eigene Funktionen\&lt;br /&gt;
\&lt;br /&gt;
## Tabellendefinition befindet sich im Package ui_Table\&lt;br /&gt;
\&lt;br /&gt;
## Funktionen aus dem main-Package müssen mit vorangestelltem Package angegeben werden (der Name main kann weggelassen werden)\&lt;br /&gt;
::FW_makeImage(&amp;quot;scene_day&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## interne uiTable-Funktionen aus dem ui_Table-Package können direkt angegeben werden\&lt;br /&gt;
temp ([Aussensensor:temperature])\&lt;br /&gt;
\&lt;br /&gt;
## eigene Funktionen können direkt angegeben werden, da man sich bereits im Package uiTable befinden\&lt;br /&gt;
scene_day()\&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==  &#039;&#039;&#039;hsv&#039;&#039;&#039;-Funktion für Farbskalierungen==&lt;br /&gt;
Mit Hilfe der hsv-Funktion können Texte, Werte oder Icons abhängig vom Wert eingefärbt werden. Es wird durch Vorgabe von Farbsättigung (saturation) und Helligkeit (lightness), linear ein Farbton für einen bestimmten Wert errechnet. Den Farbwert HUE (0 - 360) für den kleinsten sowie größten Wert kann man mit Hilfe eines Color-Pickers bestimmen. Der Rückgabewert ist ein Farbwert in der CSS-Notation.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;hsv-Funktion für Farbskalierungen&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
hsv ($value,$min_value,$max_value,$min_hue,$max_hue,$saturation,$lightness)&lt;br /&gt;
$value      # Wert, Reading&lt;br /&gt;
$min_value  # der kleinste Wert, dieser entspricht dem Farbwert $min_hue&lt;br /&gt;
$max_value  # der größte Wert, dieser entspricht dem Farbwert $max_hue&lt;br /&gt;
$min_hue    # Farbwert für den kleinsten Wert $min_value&lt;br /&gt;
$max_hue    # Farbwert für den größten Wert $max_value&lt;br /&gt;
$saturation # Farbsättigung, default 100, optional&lt;br /&gt;
$lightness  # Farbhelligkeit, default 100, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Die Funktion befindet sich im ui_Table-Package&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_hsv DOIF ##&lt;br /&gt;
attr di_uiTable_hsv uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
  ## eigene uiTable-Funktionen vom Typ 1 mit einem Rückgabewert als HTML-Code\&lt;br /&gt;
  \&lt;br /&gt;
  sub bat_icon { ## färbt das Icon &#039;measure_battery_100&#039; abhängig vom Wert mit Hilfe der Funktion hsv \&lt;br /&gt;
    my ($value)=@_;;\&lt;br /&gt;
    return(ICON(&amp;quot;measure_battery_100\@&amp;quot;.hsv($value,0,100,0,120,100,100)))\&lt;br /&gt;
  }\&lt;br /&gt;
   \&lt;br /&gt;
  sub bat_icon2 {## zusätzlich zum Farbwert wird ein entsprechendes Icon bestimmt\&lt;br /&gt;
    my($val)=@_;;\&lt;br /&gt;
	my $icon;;\&lt;br /&gt;
	if ($val==0) {\&lt;br /&gt;
	  $icon=&amp;quot;measure_battery_0&amp;quot;;;\&lt;br /&gt;
	} elsif ($val&amp;lt;=25) {\&lt;br /&gt;
	  $icon=&amp;quot;measure_battery_25&amp;quot;;;\&lt;br /&gt;
	} elsif ($val&amp;lt;=50) {\&lt;br /&gt;
	  $icon=&amp;quot;measure_battery_50&amp;quot;;;\&lt;br /&gt;
	} elsif ($val&amp;lt;=75) {\&lt;br /&gt;
	  $icon=&amp;quot;measure_battery_75&amp;quot;;;\&lt;br /&gt;
	} else {\&lt;br /&gt;
	  $icon=&amp;quot;measure_battery_100&amp;quot;;;\&lt;br /&gt;
	}\&lt;br /&gt;
	\&lt;br /&gt;
	my $output=ICON(&amp;quot;$icon\@&amp;quot;.hsv ($val,0,100,0,120,90,100));;\&lt;br /&gt;
    return($output);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
## eingefärbtes Icon 0 % entspricht rot (HSV-Wert 0), 100 % entspricht grün (HSV-Wert 120) mit Direktangabe\&lt;br /&gt;
1|ICON(&amp;quot;measure_battery_100\@&amp;quot;.hsv([bat:level],0,100,0,120,100,100))\&lt;br /&gt;
\&lt;br /&gt;
## gleiche Funktionalität mit Hilfe der oben definierten Funktion bat_icon \&lt;br /&gt;
2|bat_icon([bat:level])\&lt;br /&gt;
\&lt;br /&gt;
## Icon mit Hilfe der oben definierten Funktion bat_icon2\&lt;br /&gt;
3|bat_icon2([bat:level])\&lt;br /&gt;
\&lt;br /&gt;
## Beispiel für die Farbskaliereung von 0 bis 100 % mit der obigen Funktion bat_icon\&lt;br /&gt;
4|bat_icon(0)|bat_icon(10)|bat_icon(20)|bat_icon(30)|bat_icon(40)|bat_icon(50)|bat_icon(60)|bat_icon(70)|bat_icon(80)|bat_icon(90)|bat_icon(100)\&lt;br /&gt;
\&lt;br /&gt;
## Beispiel für die Farbskaliereung von 0 bis 100 % mit der obigen Funktion bat_icon2\&lt;br /&gt;
5|bat_icon2(0)|bat_icon2(10)|bat_icon2(20)|bat_icon2(30)|bat_icon2(40)|bat_icon2(50)|bat_icon2(60)|bat_icon2(70)|bat_icon2(80)|bat_icon2(90)|bat_icon2(100)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable DOIF hsv.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
== Eine for-Schleife mit Hilfe des &#039;&#039;&#039;FOR&#039;&#039;&#039;-Befehls ==&lt;br /&gt;
Mit Hilfe des &#039;&#039;&#039;FOR&#039;&#039;&#039;-Befehls können über eine Schleife aus einer Liste mit Elementen mehrere Tabellenzellen definiert werden. Die Elementenliste (Array) kann über eine Funktion bestimmt werden. Auf diese Weise kann z. B. eine Tabelle für mehrere Geräte einfach definiert werden.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;FOR-Befehl&#039;&#039;&#039;&lt;br /&gt;
* Der FOR-Befehl entspricht einer foreach-Schleife in Perl&lt;br /&gt;
* Syntax: &#039;&#039;&#039;FOR (&amp;lt;Array&amp;gt;,&amp;lt;Zellendefinitionen&amp;gt;)&#039;&#039;&#039;&amp;lt;br&amp;gt;&#039;&#039;&#039;&amp;lt;Array&amp;gt;&#039;&#039;&#039; eine gültige Angabe eines Arrays oder eine Perlfunktion, die ein Array liefert&amp;lt;br&amp;gt;&#039;&#039;&#039;&amp;lt;Zellendefinitionen&amp;gt;&#039;&#039;&#039; Definition einer oder mehrerer Zellen, die Angabe $_ wird durch das jeweilige Element des Arrays ersetzt&lt;br /&gt;
*&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
**{{Link2CmdRef|Anker=DOIF_aggregation|Lang=de|Label=DOIF Aggregationsfunktionen mit Perlfunktion AggrDoIf}}&lt;br /&gt;
**[[DevelopmentModuleAPI#devspec2array|devspec2array]]&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinitionen&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_for DOIF ##&lt;br /&gt;
attr di_for uiTable \&lt;br /&gt;
## Temperaturen aller Geräte, die mit &#039;T&#039; beginnen und ein Reading &#039;temperature&#039; haben, sollen in einer Tabelle visualisiert werden\&lt;br /&gt;
FOR(::AggrDoIf(&#039;@&#039;,&#039;^T_&#039;,&#039;temperature&#039;),&amp;quot;$_&amp;quot;|temp([$_:temperature:d2]))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable-FOR-temperature.png|200px|ohne]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_for DOIF ##&lt;br /&gt;
attr di_for uiTable \&lt;br /&gt;
## Anzeige des Batteriestatus aller Geräte, bei denen das Wort &#039;Fenster&#039; vorkommt, die das Readings &#039;battery&#039; haben\ &lt;br /&gt;
FOR(::AggrDoIf(&#039;@&#039;,&#039;Fenster&#039;,&#039;battery&#039;),&amp;quot;$_&amp;quot;|bat([$_:battery]))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable-FOR-battery.png|200px|ohne]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_for DOIF ##&lt;br /&gt;
attr di_for uiTable \&lt;br /&gt;
## Anzeige des Status aller Geräte im System vom Typ &#039;HMS&#039;\&lt;br /&gt;
FOR(::devspec2array(&amp;quot;TYPE=HMS&amp;quot;),&amp;quot;$_&amp;quot;|[$_])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable-FOR-HMS.png|300px|ohne]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_for DOIF ##&lt;br /&gt;
attr di_for uiTable \&lt;br /&gt;
## Elemente einer kommagetrennten Liste sollen jeweils in einer Tabellenzelle in einer Tabellenzeile angezeigt werden\&lt;br /&gt;
FOR(split(&amp;quot;,&amp;quot;,&amp;quot;Mo,Di,Mi,Do,Fr,Sa,So&amp;quot;),ui_Table::style(&amp;quot;$_&amp;quot;,&amp;quot;Darkorange&amp;quot;)|)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable-FOR-split.png|300px|ohne]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_for DOIF ##&lt;br /&gt;
attr di_for uiTable \&lt;br /&gt;
## Durch Leerzeichen getrennte Zeichenketten sollen jeweils in einer Tabellenzelle in einer Tabellenzeile angezeigt werden\&lt;br /&gt;
FOR(qw/Montag Dienstag Mittwoch Donnerstag Freitag/,&amp;quot;$_&amp;quot;|)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable-FOR-qw.png|300px|ohne]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_for DOIF ##&lt;br /&gt;
attr di_for uiTable \&lt;br /&gt;
## das Templates TPL_raum, soll vier mal aufgerufen werden: TPL_raum(1), TPL_raum(2)...\&lt;br /&gt;
## das Templates TPL_raum muss vorher definiert worden sein\&lt;br /&gt;
FOR(1..4,TPL_raum($_))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable-FOR TPL raum.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Anwendungsbeispiele&#039;&#039;&#039; ==&lt;br /&gt;
=== &#039;&#039; Visualisierung und Steuerung von &#039;&#039;&#039;Rollläden&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Im folgenden Beispiel werden Rollläden morgens hochgefahren, ebenso wird die Position aller Rollläden visualisiert. Durch Anklicken eines Icons wird der Rollladen auf die entsprechende Position bewegt. &lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* {{Link2CmdRef|Anker=DOIF_Zeitsteuerung_mit_Zeitintervallen|Lang=de|Label=Zeitsteuerung}}&lt;br /&gt;
* uiTable-Funktion [[DOIF/uiTable Schnelleinstieg#Rollladen: Visualisierung und Steuerung mit Hilfe der Funktion shutter|shutter]]&lt;br /&gt;
* uiTable-Funktion [[DOIF/uiTable Schnelleinstieg#Textformatierungen mit Hilfe der Funktion style|style]]&lt;br /&gt;
* [[DOIF/uiTable Schnelleinstieg#uiTable-Templates|Templates]]&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DI_Rollladen DOIF (([Dunkelheit] eq &amp;quot;off&amp;quot; and [06:25-09:00|8]) or [09:00|7]) \&lt;br /&gt;
  ((set R_W_S,R_W_W[1-3] on)) ## Hochfahren der Rollläden im Erdgeschoss morgens\&lt;br /&gt;
DOELSEIF ([Dunkelheit] eq &amp;quot;on&amp;quot;)&lt;br /&gt;
attr DI_Rollladen cmdState oben|unten&lt;br /&gt;
attr DI_Rollladen devStateIcon unten:status_night oben:scene_day&lt;br /&gt;
attr DI_Rollladen icon fts_shutter_automatic&lt;br /&gt;
attr DI_Rollladen uiTable {\&lt;br /&gt;
   package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
## Template für ein Fenster\&lt;br /&gt;
DEF TPL_shutter(&amp;quot;$1&amp;quot;|shutter([$1:pct]))\&lt;br /&gt;
\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
style(&amp;quot;Dachgeschoss&amp;quot;,&amp;quot;Darkorange&amp;quot;)|&amp;quot;&amp;quot;\&lt;br /&gt;
TPL_shutter(R_Dachboden)\&lt;br /&gt;
style(&amp;quot;erstes Geschoss&amp;quot;,&amp;quot;Darkorange&amp;quot;)|&amp;quot;&amp;quot;\&lt;br /&gt;
TPL_shutter(R_Bad)\&lt;br /&gt;
TPL_shutter(R_Kinderzimmer1_O)\&lt;br /&gt;
TPL_shutter(R_Kinderzimmer1_S)\&lt;br /&gt;
TPL_shutter(R_Kinderzimmer2_S)\&lt;br /&gt;
TPL_shutter(R_Kinderzimmer2_W1)\&lt;br /&gt;
TPL_shutter(R_Kinderzimmer2_W2)\&lt;br /&gt;
style(&amp;quot;Erdgeschoss&amp;quot;,&amp;quot;Darkorange&amp;quot;)|&amp;quot;&amp;quot;\&lt;br /&gt;
TPL_shutter(R_Kueche)\&lt;br /&gt;
TPL_shutter(R_W_S)\&lt;br /&gt;
TPL_shutter(R_W_W1)\&lt;br /&gt;
TPL_shutter(R_W_W2)\&lt;br /&gt;
TPL_shutter(R_W_W3)\&lt;br /&gt;
style(&amp;quot;Keller&amp;quot;,&amp;quot;Darkorange&amp;quot;)|&amp;quot;&amp;quot;\&lt;br /&gt;
TPL_shutter(R_Keller)\&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis des Anwendungsbeispiels in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable Rollladen.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;Anzahl der Tage bis zur &#039;&#039;&#039;Abfall-Entsorgung&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Mit Hilfe des Kalender-Moduls werden die verbleibenden Tage bis zur Abfall-Entsorgung der jeweiligen Tonne berechnet und mit Hilfe von uiTable visualisiert. Wenn der Tag der Entsorgung bevorsteht, wird er farbig gekennzeichnet. Vorausgesetzt wird die Definition des Kalenders namens &#039;cal&#039; mit Hilfe des Moduls [[Calendar]]. Dieser muss die Termine der Abfallentsorgung der Tonnen beinhalten. Im Beispiel wird nach Stichwörtern: &amp;quot;Altpapier&amp;quot;, &amp;quot;Restmüll&amp;quot;, &amp;quot;Bio&amp;quot;, &amp;quot;Gelber&amp;quot; und &amp;quot;Grünschnitt&amp;quot; im Kalender gesucht. &lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* FHEM-Modul [[Calendar]]&lt;br /&gt;
* ui_Table Funktion [[DOIF/uiTable Schnelleinstieg#Icon-Darstellung mit Text mit Hilfe der Funktion icon_label|icon_label]]&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Abfall DOIF subs {\&lt;br /&gt;
  ## Die Funktion &#039;days&#039; sucht nach dem Ereignis $event im Kalender und berechnet die Anzahl der verbleibenden Tage und legt sie im entsprechendem Reading $reading des DOIF-Moduls ab\&lt;br /&gt;
  sub days \&lt;br /&gt;
  {\&lt;br /&gt;
    my ($event,$reading)=@_;;\&lt;br /&gt;
    set_Reading($reading,fhem(&#039;get cal events timeFormat:&amp;quot;%j&amp;quot; filter:field(summary)=~&amp;quot;&#039;.$event.&#039;&amp;quot; limit:count=1,from=0 format:custom=&amp;quot;$T1&amp;quot;&#039;)-::strftime (&#039;%j&#039;, localtime()),1)\&lt;br /&gt;
  }\&lt;br /&gt;
  ## Die Funktion &#039;update&#039; bestimmt die verbleibenden Tage mit Hilfe der obigen Funktion &#039;days&#039; für die jeweiligen Tonnen\&lt;br /&gt;
  sub update\&lt;br /&gt;
  {\&lt;br /&gt;
    days(&amp;quot;Altpapier&amp;quot;,&amp;quot;altpapier&amp;quot;);;days(&amp;quot;Restmüll&amp;quot;,&amp;quot;restmuell&amp;quot;);;days(&amp;quot;Bio&amp;quot;,&amp;quot;bio&amp;quot;);;days(&amp;quot;Gelber&amp;quot;,&amp;quot;gelbe_tonne&amp;quot;);;days(&amp;quot;Grünschnitt&amp;quot;,&amp;quot;gruenschnitt&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
## Beim Start, um 02:00 Uhr und 08:00 Uhr wird zeitverzögert die obige Funktion &#039;update&#039; aufgerufen\&lt;br /&gt;
init {[02:00];;[08:00];;set_Exec(&amp;quot;Timer&amp;quot;,60,&#039;update()&#039;);;\&lt;br /&gt;
}&lt;br /&gt;
attr Abfall uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
  $TC{0..4}=&amp;quot;align=&#039;center&#039;&amp;quot;;;\&lt;br /&gt;
  $SHOWNOSTATE=1;;\&lt;br /&gt;
 \&lt;br /&gt;
  ## die Funktion &#039;ic&#039; benutzt die Funktion &#039;icon_label&#039; für die Darstellung des Icons, abhängig von der Anzahl der Tage wird die Anzahl in grün bzw. rot eingefärbt \&lt;br /&gt;
  sub ic\&lt;br /&gt;
  {\&lt;br /&gt;
    my ($icon,$days)=@_;;\&lt;br /&gt;
    icon_label($icon,$days,&amp;quot;white&amp;quot;,$days &amp;gt; 1 ? &amp;quot;green&amp;quot;:&amp;quot;red&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
## Tabellendefinition, die einzelnen Tonnen werden mit Hilfe der obigen Funkton &#039;ic&#039; dargestellt\&lt;br /&gt;
\&lt;br /&gt;
ic (&amp;quot;Abfalltonne-Recycling-Logo\@yellow&amp;quot;,[$SELF:gelbe_tonne])|\&lt;br /&gt;
ic (&amp;quot;Abfalltonne-Recycling-Logo\@blue&amp;quot;,[$SELF:altpapier])|\&lt;br /&gt;
ic (&amp;quot;Abfalltonne\@gray&amp;quot;,[$SELF:restmuell])|\&lt;br /&gt;
ic (&amp;quot;Abfalltonne-Recycling-Logo\@green&amp;quot;,[$SELF:bio])|\&lt;br /&gt;
ic (&amp;quot;Gartenabfall\@green&amp;quot;,[$SELF:gruenschnitt])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:Anwendungsbeispiel Abfall.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;Visualisierung: &#039;&#039;&#039;offene Fenster&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Alle offenen Fenster werden aufgelistet und mit entsprechendem Icon visualisiert.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* Attribut {{Link2CmdRef|Anker=DOIF_DOIF_Readings|Lang=de|Label=DOIF_Readings}}&lt;br /&gt;
* DOIF-{{Link2CmdRef|Anker=DOIF_aggregation|Lang=de|Label=Aggregationsfunktionen}}&lt;br /&gt;
* uiTable-Funktion [[DOIF/uiTable Schnelleinstieg#Icon-Darstellung mit Hilfe der Funktion icon|icon]]&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_windows DOIF ## Visualisierung offener Fenster, Fenster-Devices enden mit &amp;quot;Fenster&amp;quot; im Namen&lt;br /&gt;
attr di_uiTable_windows DOIF_Readings windows:[@as(&amp;lt;br&amp;gt;)&amp;quot;Fenster$&amp;quot;:state:&amp;quot;open&amp;quot;,&amp;quot;keine&amp;quot;]&lt;br /&gt;
attr di_uiTable_windows uiTable {package ui_Table;;}\&lt;br /&gt;
icon([$SELF:windows],&amp;quot;fts_window_1w_open\@DarkOrange&amp;quot;,&amp;quot;fts_window_1w&amp;quot;,&amp;quot;.*&amp;quot;,&amp;quot;keine&amp;quot;)|[$SELF:windows]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable windows closed.png|mini|ohne]]&lt;br /&gt;
[[Datei:UiTable windows open.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;Visualisierung: &#039;&#039;&#039;aktuelle Wetterlage&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Regenrader animiert, aktuelle Temperatur und Feuchte vom Sensor, aktuelle Wetterlage sowie Wettervorhersage der nächsten Tage. Über entsprechende Weblinks werden Bilder aus dem WWW in der Tabelle visualisiert. Im Gegensatz zu lokalen Sensoren, muss für die Aktualisierung der WWW-Elemente in der jeweiligen Webinstanz (FHEMWEB) das refresh-Attribut gesetzt werden. &lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* DWD [https://www.dwd.de/DE/Home/home_node.html Homepage]&lt;br /&gt;
* Regenradar [https://www.dwd.de/DE/wetter/wetterundklima_vorort/_node.html Radarfilm BRD]&lt;br /&gt;
* aktuelles Wetter [https://www.dwd.de/DE/wetter/wetterundklima_vorort/nordrhein-westfalen/nrw_node.html NRW]&lt;br /&gt;
* Wetteronline [https://www.wetteronline.de/wetter-widget eignes Widget]&lt;br /&gt;
* &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_wetter DOIF ##&lt;br /&gt;
attr di_uiTable_wetter uiTable {\&lt;br /&gt;
 package ui_Table;;\&lt;br /&gt;
 $TC{1}=&amp;quot;align=&#039;center&#039;&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
## das Attribut &#039;refresh&#039; der Webinstanz für ein Wandtablet wurde auf 900 gesetzt, damit die Bilder alle 15 Minuten aktualisiert werden \&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
## Regenradar BRD\&lt;br /&gt;
&#039;&amp;lt;img src=&amp;quot;https://www.dwd.de/DWD/wetter/radar/radfilm_brd_akt.gif&amp;quot; height=&amp;quot;365px&amp;quot; width=&amp;quot;365px&amp;quot;&amp;gt;&#039;|\&lt;br /&gt;
\&lt;br /&gt;
## Aktuelle Temperatur und Feuchtigkeit vom lokalen sensor\&lt;br /&gt;
temp([Aussensensor:temperature],40),hum ([Aussensensor:humidity],30),\&lt;br /&gt;
\&lt;br /&gt;
## aktuelle Wetterlage NRW\&lt;br /&gt;
&amp;quot;&amp;lt;img src =&#039;https://www.dwd.de/DE/wetter/wetterundklima_vorort/nordrhein-westfalen/_functions/bildgalerie/wetter_aktuell.jpg?view=nasImage&amp;amp;nn=561200&#039; height=&#039;255px&#039; width=&#039;255px&#039;&amp;gt;&amp;quot;|\&lt;br /&gt;
\&lt;br /&gt;
## Wettervorhersage\&lt;br /&gt;
&amp;quot;&amp;lt;iframe marginheight=&#039;0&#039; marginwidth=&#039;0&#039; scrolling=&#039;no&#039; width=&#039;300&#039; height=&#039;365&#039; name=&#039;FC3&#039; style=&#039;border:1px solid;;border-color:#00537f;;&#039; src=&#039;https://api.wetteronline.de/wetterwidget?gid=x0677&amp;amp;modeid=FC3&amp;amp;seourl=juelich&amp;amp;locationname=Jülich&amp;amp;lang=de&#039;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;quot;\&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable wetter.png|600px|links]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;Visualisierung: &#039;&#039;&#039;Wetterstation&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Die vorgestellte Lösung funktioniert ohne Anmeldung beim Wetterdienst und ohne Nutzung von API.&lt;br /&gt;
Über den Wetterdienst: https://www.wunderground.com/ werden sehr viele private Wifi-Wetterstationen eingebunden. Das kann man sich zunutze machen, indem man zunächst in seiner Umgebung nach Wetterstationen des Dienstes sucht - oft findet man im Umkreis von wenigen Kilometern schon einige Stationen, die rege Wetterdaten liefern. Danach definiert man über HTTPMOD seine Station und visualisiert diese anschließend.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* Wunderground [https://wunderground.com/ Homepage]&lt;br /&gt;
* svg-Funktion [https://wiki.fhem.de/wiki/DOIF/uiTable_Schnelleinstieg#Anzeige_eines_Werteverlaufs_und_des_aktuellen_Wertes_mit_Hilfe_der_SVG-Funktion_card card]&lt;br /&gt;
* svg-Funktionen [https://wiki.fhem.de/wiki/DOIF/uiTable_Schnelleinstieg#icon_ring-Funktionen icon_ring]&lt;br /&gt;
}}&lt;br /&gt;
Definition einer Station in der Nachbarschaft. &amp;lt;StationsID&amp;gt; muss gegen die korrekte Stationsnummer ersetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Wetter HTTPMOD https://www.wunderground.com/dashboard/pws/&amp;lt;StationsID&amp;gt;&lt;br /&gt;
attr Wetter enableControlSet 1&lt;br /&gt;
attr Wetter reading01Name Wind&lt;br /&gt;
attr Wetter reading01Regex wu-unit .{109}&amp;gt;(\d+\.\d)&lt;br /&gt;
attr Wetter reading02Name Windboeen&lt;br /&gt;
attr Wetter reading02Regex wu-unit-speed .{109}&amp;gt;(\d+\.\d)&lt;br /&gt;
attr Wetter reading03Name Windrichtung&lt;br /&gt;
attr Wetter reading03Regex (\d+)deg\).{84}Wind-Marker&lt;br /&gt;
attr Wetter reading04Name Regen&lt;br /&gt;
attr Wetter reading04Regex wu-unit-rainRate .{109}&amp;gt;(\d+\.\d\d)&lt;br /&gt;
attr Wetter reading05Name RegenGesamt&lt;br /&gt;
attr Wetter reading05Regex wu-unit-rain .{109}&amp;gt;(\d+\.\d\d)&lt;br /&gt;
attr Wetter reading06Name Temperatur&lt;br /&gt;
attr Wetter reading06Regex wu-unit-temperature .{127}&amp;gt;(\d+.\d)&lt;br /&gt;
attr Wetter reading07Name Feuchtigkeit&lt;br /&gt;
attr Wetter reading07Regex wu-unit-humidity .{109}&amp;gt;(\d\d)&lt;br /&gt;
attr Wetter reading08Name UV&lt;br /&gt;
attr Wetter reading08Regex UV&amp;lt;.{268}&amp;gt;(\d)&lt;br /&gt;
attr Wetter reading09Name Luftdruck&lt;br /&gt;
attr Wetter reading09Regex PRESSURE&amp;lt;.{285}&amp;gt;(\d+.\d+)&lt;br /&gt;
attr Wetter reading10Name TemperaturGefuehlt&lt;br /&gt;
attr Wetter reading10Regex wu-unit is-degree-visible .{109}&amp;gt;(\d+.\d)&lt;br /&gt;
attr Wetter reading11Name TaupunktTemp&lt;br /&gt;
attr Wetter reading11Regex DEWPOINT.{306}&amp;gt;(\d+.\d)&lt;br /&gt;
attr Wetter reading12Name Sonnenstrahlung&lt;br /&gt;
attr Wetter reading12Regex Solar radiation&amp;lt;.{549}&amp;gt;(\d+.\d+)&lt;br /&gt;
attr Wetter timeout 10&lt;br /&gt;
attr Wetter userReadings WindKm {sprintf(&amp;quot;%1.1f&amp;quot;,ReadingsVal($name,&amp;quot;Wind&amp;quot;,0)*1.60934)},\&lt;br /&gt;
WindboeenKm {sprintf(&amp;quot;%1.1f&amp;quot;,ReadingsVal($name,&amp;quot;Windboeen&amp;quot;,0)*1.60934)},\&lt;br /&gt;
WindrichtungGrad {ReadingsVal($name,&amp;quot;Windrichtung&amp;quot;,0)-180},\&lt;br /&gt;
RegenMm {ReadingsVal($name,&amp;quot;Regen&amp;quot;,0)*25.4},\&lt;br /&gt;
RegenGesamtMm {ReadingsVal($name,&amp;quot;RegenGesamt&amp;quot;,0)*25.4},\&lt;br /&gt;
TemperaturC {sprintf(&amp;quot;%1.1f&amp;quot;,(ReadingsVal($name,&amp;quot;Temperatur&amp;quot;,0)-32)*5/9)},\&lt;br /&gt;
TaupunktTempC {sprintf(&amp;quot;%1.1f&amp;quot;,(ReadingsVal($name,&amp;quot;TaupunktTemp&amp;quot;,0)-32)*5/9)},\&lt;br /&gt;
LuftdruckHpa {sprintf(&amp;quot;%d&amp;quot;,ReadingsVal($name,&amp;quot;Luftdruck&amp;quot;,0)*33.8639)},\&lt;br /&gt;
TemperaturGefuehltC {sprintf(&amp;quot;%1.1f&amp;quot;,(ReadingsVal($name,&amp;quot;TemperaturGefuehlt&amp;quot;,0)-32)*5/9)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun erfolgt die Visualisierung der Daten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_Wetter_ring DOIF ##&lt;br /&gt;
attr di_Wetter_ring uiTable {package ui_Table;;}\&lt;br /&gt;
\&lt;br /&gt;
icon_temp_hum_ring(&amp;quot;temp_outside&amp;quot;,[Wetter:TemperaturC],[Wetter:Feuchtigkeit],undef,undef,150)|\&lt;br /&gt;
icon_temp_ring (&amp;quot;temp_windchill&amp;quot;,[Wetter:TemperaturGefuehltC],undef,undef,150) |\&lt;br /&gt;
icon_temp_ring (&amp;quot;temperature_humidity&amp;quot;,[Wetter:TaupunktTempC],undef,undef,150) |\&lt;br /&gt;
icon_ring2([Wetter:WindKm] &amp;gt; 0 ? &amp;quot;wind&amp;quot;.&amp;quot;,1,0,0,&amp;quot;.[Wetter:WindrichtungGrad]:&amp;quot;no_wind&amp;quot;,[Wetter:WindKm],0,50,120,0,&amp;quot;km/h&amp;quot;,150,undef,1,[Wetter:WindboeenKm],0,50,120,0,&amp;quot;km/h&amp;quot;,undef,1) |\&lt;br /&gt;
icon_ring2(&amp;quot;weather_rain_gauge&amp;quot;,[Wetter:RegenMm],0,10,180,270,&amp;quot;mm/h&amp;quot;,150,undef,1,[Wetter:RegenGesamtMm],0,50,180,270,&amp;quot;mm&amp;quot;,undef,1)|\&lt;br /&gt;
icon_ring2(&amp;quot;sani_solar&amp;quot;,[Wetter:UV],0,10,100,30,&amp;quot;UV&amp;quot;,150,undef,0,[Wetter:Sonnenstrahlung],0,1000,100,30,&amp;quot;Watt/m²&amp;quot;,undef,0)|\&lt;br /&gt;
icon_ring (&amp;quot;weather_barometric_pressure&amp;quot;,[Wetter:LuftdruckHpa],980,1047,0,120,&amp;quot;hPa&amp;quot;,0,150)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable ringwetter.png|600px|links]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier ein Beispiel der Visualisierung mit Verlauf der letzten drei Tage mit Hilfe der svg-Funktion &#039;&#039;&#039;card&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_Wetter DOIF ##&lt;br /&gt;
attr di_Wetter icon weather_wind&lt;br /&gt;
attr di_Wetter uiTable {package ui_Table;;}\&lt;br /&gt;
##  card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness)\&lt;br /&gt;
\&lt;br /&gt;
card([Wetter:TemperaturC:col3d],&amp;quot;Außentemperatur&amp;quot;,&amp;quot;temp_outside&amp;quot;,-10,60,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue)|\&lt;br /&gt;
card([Wetter:TemperaturGefuehltC:col3d],&amp;quot;gefühlte Temperatur&amp;quot;,&amp;quot;temp_windchill&amp;quot;,-10,60,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue)|\&lt;br /&gt;
card([Wetter:TaupunktTempC:col3d],&amp;quot;Taupunkttemperatur&amp;quot;,&amp;quot;temperature_humidity&amp;quot;,-10,60,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue)|\&lt;br /&gt;
card([Wetter:Feuchtigkeit:col3d],&amp;quot;Außenfeuchtigkeit&amp;quot;,&amp;quot;temperature_humidity&amp;quot;,0,100,undef,undef,&amp;quot;%&amp;quot;,\&amp;amp;hum_hue)|\&lt;br /&gt;
card([Wetter:WindKm:col3d],&amp;quot;Wind&amp;quot;,[Wetter:WindKm] &amp;gt; 0 ? &amp;quot;wind&amp;quot;.&amp;quot;,1,0,0,&amp;quot;.[Wetter:WindrichtungGrad]:&amp;quot;no_wind&amp;quot;,0,30,90,30,&amp;quot;km/h&amp;quot;,undef,1)\&lt;br /&gt;
card([Wetter:WindboeenKm:col3d],&amp;quot;Windböen&amp;quot;,&amp;quot;weather_wind&amp;quot;,0,30,90,30,&amp;quot;km/h&amp;quot;,undef,1)|\&lt;br /&gt;
card([Wetter:RegenMm:col3d],&amp;quot;Regen&amp;quot;,&amp;quot;weather_rain_gauge&amp;quot;,0,10,180,270,&amp;quot;mm/h&amp;quot;)|\&lt;br /&gt;
card([Wetter:RegenGesamtMm:col3d],&amp;quot;Regengesamt&amp;quot;,&amp;quot;weather_rain_gauge&amp;quot;,0,50,180,270,&amp;quot;mm&amp;quot;)|\&lt;br /&gt;
##card([Wetter:UV:col3d],&amp;quot;UV-Strahlung&amp;quot;,&amp;quot;sani_solar&amp;quot;,0,7,100,30,&amp;quot;UV&amp;quot;,undef,0)|\&lt;br /&gt;
card([Wetter:Sonnenstrahlung:col3d],&amp;quot;Sonnenstrahlung&amp;quot;,&amp;quot;sani_solar&amp;quot;,0,1000,30,90,&amp;quot;Watt/m²&amp;quot;,undef,0)|\&lt;br /&gt;
card([Wetter:LuftdruckHpa:col3d],&amp;quot;Luftdruck&amp;quot;,&amp;quot;weather_barometric_pressure&amp;quot;,980,1047,30,90,&amp;quot;hPa&amp;quot;,undef,0)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable svgwetter.png|600px|links]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ohne Angabe der Überschrift (undef für $header setzen) lässt sich eine kompaktere Darstellung erzielen:&lt;br /&gt;
&lt;br /&gt;
[[Datei:UiTable svgwetteroh.png|600px|links]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;Visualisierung: &#039;&#039;&#039;aktueller Spritpreis&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Der aktuelle Spritpreis einer Tankstelle wird ermittelt und mit seinem zeitlichen Verlauf visualisiert.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* svg-Funktion [[DOIF/uiTable_Schnelleinstieg#ring-Funktionen|ring]]&lt;br /&gt;
* svg-Funktion [[DOIF/uiTable_Schnelleinstieg#Anzeige_eines_Werteverlaufs_und_des_aktuellen_Wertes_mit_Hilfe_der_SVG-Funktion_card|card]]&lt;br /&gt;
* Tankstelle bestimmen [https://www.clever-tanken.de/ Clever tanken]&lt;br /&gt;
* Modul [[HTTPMOD]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Zunächst wird ein HTTPMOD-Modul für den aktuellen Spritpreis definiert, dabei ist &amp;lt;Stations-ID&amp;gt; durch die ID der Tankstelle zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Tankstelle HTTPMOD http://www.clever-tanken.de/tankstelle_details/&amp;lt;Stations-ID&amp;gt; 300&lt;br /&gt;
attr Tankstelle devStateIcon {ui_Table::ring(ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Diesel&amp;quot;,0),1.00,1.40,120,0,&amp;quot;Diesel&amp;quot;,90,undef,2).&amp;quot; &amp;quot;.ui_Table::ring(ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SuperE5&amp;quot;,0),1.10,1.60,120,0,&amp;quot;E5&amp;quot;,90,undef,2)}&lt;br /&gt;
attr Tankstelle enableControlSet 1&lt;br /&gt;
attr Tankstelle event-on-change-reading .*&lt;br /&gt;
attr Tankstelle group Spritpreise&lt;br /&gt;
attr Tankstelle reading01Name Diesel&lt;br /&gt;
attr Tankstelle reading01Regex &amp;quot;current-price-1&amp;quot;&amp;gt;(\d.\d{2})&lt;br /&gt;
attr Tankstelle reading02Name SuperE5&lt;br /&gt;
attr Tankstelle reading02Regex &amp;quot;current-price-2&amp;quot;&amp;gt;(\d.\d{2})&lt;br /&gt;
attr Tankstelle room Spritpreise&lt;br /&gt;
attr Tankstelle timeout 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:Di uiTable Tankstelle.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
Visualisierung der Preisentwicklung der letzten 24 Stunden: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod sprit DOIF ##&lt;br /&gt;
attr sprit uiTable {package ui_Table;;}\&lt;br /&gt;
card([Tankstelle:Diesel:col24],&amp;quot;Diesel&amp;quot;,&amp;quot;fuel&amp;quot;,&amp;quot;1.00&amp;quot;,&amp;quot;1.40&amp;quot;,120,0,&amp;quot;Diesel €&amp;quot;,undef,&amp;quot;2&amp;quot;,&amp;quot;,,1&amp;quot;)\&lt;br /&gt;
card([Tankstelle:SuperE5:col24],&amp;quot;Super E5&amp;quot;,&amp;quot;fuel&amp;quot;,&amp;quot;1.10&amp;quot;,&amp;quot;1.60&amp;quot;,120,0,&amp;quot;Super €&amp;quot;,undef,&amp;quot;2&amp;quot;,&amp;quot;,,1&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:Di uiTable sprit.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;Visualisierung: &#039;&#039;&#039;aktuelle Corona-7-Tage-Inzidenz&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Die aktuellen Inzidenzwerte werden vom RKI ausgelesen und deren Verlauf visualisiert.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* svg-Funktion [[DOIF/uiTable_Schnelleinstieg#ring-Funktionen|ring]]&lt;br /&gt;
* svg-Funktion [[DOIF/uiTable_Schnelleinstieg#Anzeige_eines_Werteverlaufs_und_des_aktuellen_Wertes_mit_Hilfe_der_SVG-Funktion_card|card]]&lt;br /&gt;
* Modul [[JsonMod]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Zunächst wird ein JsonMod Device für das Auslesen der Inzidenzzahlen definiert. Die gewünschten Regionen müssen für eigene Bedürfnisse angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod RKI7 JsonMod https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_Landkreisdaten/FeatureServer/0/query?where=1%3D1&amp;amp;outFields=last_update,cases7_per_100k,BEZ,BEM,GEN,BL,county&amp;amp;returnGeometry=false&amp;amp;outSR=4326&amp;amp;f=json&lt;br /&gt;
attr RKI7 readingList multi(jsonPath(&amp;quot;\$.features[?(\@.attributes.GEN in [&#039;Städteregion Aachen&#039;, &#039;Düren&#039;, &#039;Heinsberg&#039;])]&amp;quot;), property(&#039;attributes.GEN&#039;), sprintf(&#039;%.1f&#039;, property(&#039;attributes.cases7_per_100k&#039;)));;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Visualisierung der Inzidenzzahlen der letzten sieben Tage: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_corona DOIF ##&lt;br /&gt;
attr di_corona uiTable {package ui_Table}\&lt;br /&gt;
card([RKI7:Duren:col1w],&amp;quot;Düren&amp;quot;,&amp;quot;coronavirus&amp;quot;,0,200,120,0,&amp;quot;Fälle&amp;quot;)|\&lt;br /&gt;
card([RKI7:Heinsberg:col1w],&amp;quot;Heinsberg&amp;quot;,&amp;quot;coronavirus&amp;quot;,0,200,120,0,&amp;quot;Fälle&amp;quot;)|\&lt;br /&gt;
card([RKI7:Stadteregion_Aachen:col1w],&amp;quot;Aachen&amp;quot;,&amp;quot;coronavirus&amp;quot;,0,200,120,0,&amp;quot;Fälle&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:uiTable_Inzidenz.png|600px|links]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039; Visualisierung und Steuerung: &#039;&#039;&#039;Heiztherme&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Im folgenden Beispiel wurde eine Heiztherme über einen ebus-Adapter in FHEM eingebunden. Die Heizungsdaten werden über MQTT ausgelesen und anschließend visualisiert. Die vorgestellten Visualisierungsbeispiele können ebenso im funktionslosen DOIF mit Hilfe des uiTable-Attriutes auf bereits existierende Readings des eigenen Systems angewendet werden. &lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* svg-Funktion [[DOIF/uiTable_Schnelleinstieg#icon_ring-Funktionen|icon_ring]]&lt;br /&gt;
* svg-Funktion [[DOIF/uiTable_Schnelleinstieg#Anzeige_eines_Werteverlaufs_und_des_aktuellen_Wertes_mit_Hilfe_der_SVG-Funktion_card|card]]&lt;br /&gt;
* Commandref [https://fhem.de/commandref_DE.html#DOIF_Perl_Modus DOIF Perl-Modus]&lt;br /&gt;
* ebus-Adapter [https://ebusd.de/ ebusd]&lt;br /&gt;
* ebus-Wiki [[EBUS|ebus]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Definition eines MQTT2-Devices für die Kommunikation mit der Therme über einen ebus-Adapter.&lt;br /&gt;
&lt;br /&gt;
Im diesem Fall wurde eine Vaillanttherme eingebunden, die meisten Readings wurden automatisch vom MQTT2-Server angelegt. Die Anbindung ist gerätespezifisch und unterscheidet sich je nach Gerättyp.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod vaillant MQTT2_DEVICE ebusd_bai&lt;br /&gt;
attr vaillant IODev MQTT2_FHEM_Server&lt;br /&gt;
attr vaillant devStateStyle style=&amp;quot;text-align:left&amp;quot;&lt;br /&gt;
attr vaillant event-on-change-reading .*&lt;br /&gt;
attr vaillant group Ebus&lt;br /&gt;
attr vaillant icon sani_boiler_temp&lt;br /&gt;
attr vaillant jsonMap Status01_0_value:Vorlauf Status01_0_name:0\&lt;br /&gt;
Status01_1_value:Ruecklauf Status01_1_name:0\&lt;br /&gt;
Status01_2_value:Aussentemp Status01_2_name:0\&lt;br /&gt;
Status01_3_value:Warmwasser Status01_3_name:0\&lt;br /&gt;
Status01_4_value:WWSpeicher Status01_4_name:0\&lt;br /&gt;
Status01_5_value:Pumpenstatus Status01_5_name:0\&lt;br /&gt;
Flame_0_value:Flame Flame_0_name:0\&lt;br /&gt;
Storageloadpump_percent0_value:Storageloadpump\&lt;br /&gt;
FlowTempDesired_temp_value:VorlaufSoll\&lt;br /&gt;
Hc1HeatCurve_0_value:HeizKennlinie Hc1HeatCurve_0_name:0\&lt;br /&gt;
HolidayEndPeriod_hto_value:FerienEnde\&lt;br /&gt;
HolidayStartPeriod_hfrom_value:FerienBeginn\&lt;br /&gt;
PumpPower_0_value:PumpenLeistung PumpPower_0_name:0\&lt;br /&gt;
PrimaryCircuitFlowrate_uin100_value:Umlaufmenge\&lt;br /&gt;
z1DayTemp_tempv_value:TagSolltemp\&lt;br /&gt;
z1NightTemp_tempv_value:NachtSolltemp\&lt;br /&gt;
FanSpeed_0_value:LuefterDrehzahl FanSpeed_0_name:0\&lt;br /&gt;
WaterPressure_pressv_value:Wasserdruck\&lt;br /&gt;
z1OpMode_opmode_value:Heizmodus&lt;br /&gt;
attr vaillant model eBus_bai_jsonmap&lt;br /&gt;
attr vaillant readingList ebusd/bai/PumpHours:.* { json2nameValue($EVENT, &#039;PumpHours_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/WPPostrunTime:.* { json2nameValue($EVENT, &#039;WPPostrunTime_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PowerValue:.* { json2nameValue($EVENT, &#039;PowerValue_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/StorageExitTemp:.* { json2nameValue($EVENT, &#039;StorageExitTemp_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/global/version:.* version\&lt;br /&gt;
ebusd/global/running:.* running\&lt;br /&gt;
ebusd/scan\x5c\x2e08/:.* { json2nameValue($EVENT, &#039;scan.08_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/scan\x5c\x2e08/id:.* { json2nameValue($EVENT, &#039;id_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/global/uptime:.* uptime\&lt;br /&gt;
ebusd/global/signal:.* signal\&lt;br /&gt;
ebusd/scan\x5c\x2e15/:.* { json2nameValue($EVENT, &#039;scan.15_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/scan\x5c\x2e15/id:.* { json2nameValue($EVENT, &#039;id_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/FanSpeed:.* { json2nameValue($EVENT, &#039;FanSpeed_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PumpPower:.* { json2nameValue($EVENT, &#039;PumpPower_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/broadcast/vdatetime:.* { json2nameValue($EVENT, &#039;vdatetime_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/broadcast/outsidetemp:.* { json2nameValue($EVENT, &#039;outsidetemp_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/DateTime:.* { json2nameValue($EVENT, &#039;DateTime_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/global/updatecheck:.* updatecheck\&lt;br /&gt;
ebusd/bai/DCFTimeDate:.* { json2nameValue($EVENT, &#039;DCFTimeDate_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PumpPowerDesired:.* { json2nameValue($EVENT, &#039;PumpPowerDesired_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/HwcImpellorSwitch:.* { json2nameValue($EVENT, &#039;HwcImpellorSwitch_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/ReturnTemp:.* { json2nameValue($EVENT, &#039;ReturnTemp_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/HwcStorageTempBottom:.* { json2nameValue($EVENT, &#039;HwcStorageTempBottom_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/HwcTempDesired:.* { json2nameValue($EVENT, &#039;HwcTempDesired_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/FanPWMSum:.* { json2nameValue($EVENT, &#039;FanPWMSum_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/HcHours:.* { json2nameValue($EVENT, &#039;HcHours_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/HoursTillService:.* { json2nameValue($EVENT, &#039;HoursTillService_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PumpHwcFlowNumber:.* { json2nameValue($EVENT, &#039;PumpHwcFlowNumber_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/WP:.* { json2nameValue($EVENT, &#039;WP_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/WaterPressure:.* { json2nameValue($EVENT, &#039;WaterPressure_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PrimaryCircuitFlowrate:.* { json2nameValue($EVENT, &#039;PrimaryCircuitFlowrate_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/Flame:.* { json2nameValue($EVENT, &#039;Flame_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/Storageloadpump:.* { json2nameValue($EVENT, &#039;Storageloadpump_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/Status01:.* { json2nameValue($EVENT, &#039;Status01_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/FlowTempDesired:.* { json2nameValue($EVENT, &#039;FlowTempDesired_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/FrostOverRideTime:.* { json2nameValue($EVENT, &#039;FrostOverRideTime_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/Hc1ActualFlowTempDesired:.* { json2nameValue($EVENT, &#039;Hc1ActualFlowTempDesired_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/Hc1AutoOffMode:.* { json2nameValue($EVENT, &#039;Hc1AutoOffMode_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/Hc1CircuitType:.* { json2nameValue($EVENT, &#039;Hc1CircuitType_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/Hc1HeatCurve:.* { json2nameValue($EVENT, &#039;Hc1HeatCurve_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/HcStorageTempBottom:.* { json2nameValue($EVENT, &#039;HcStorageTempBottom_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/HcStorageTempTop:.* { json2nameValue($EVENT, &#039;HcStorageTempTop_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/HolidayTemp:.* { json2nameValue($EVENT, &#039;HolidayTemp_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/OpMode:.* { json2nameValue($EVENT, &#039;OpMode_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1RoomTemp:.* { json2nameValue($EVENT, &#039;z1RoomTemp_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1SFMode:.* { json2nameValue($EVENT, &#039;z1SFMode_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1OpMode:.* { json2nameValue($EVENT, &#039;z1OpMode_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/Time:.* { json2nameValue($EVENT, &#039;Time_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/EbusVoltage:.* { json2nameValue($EVENT, &#039;EbusVoltage_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/extWP:.* { json2nameValue($EVENT, &#039;extWP_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/FanStarts:.* { json2nameValue($EVENT, &#039;FanStarts_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1NightTemp:.* { json2nameValue($EVENT, &#039;z1NightTemp_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1DayTemp:.* { json2nameValue($EVENT, &#039;z1DayTemp_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/HolidayStartPeriod:.* { json2nameValue($EVENT, &#039;HolidayStartPeriod_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/HolidayEndPeriod:.* { json2nameValue($EVENT, &#039;HolidayEndPeriod_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1Timer.Monday:.* { json2nameValue($EVENT, &#039;z1Timer.Monday_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1Timer.Tuesday:.* { json2nameValue($EVENT, &#039;z1Timer.Tuesday_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1Timer.Wednesday:.* { json2nameValue($EVENT, &#039;z1Timer.Wednesday_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1Timer.Thursday:.* { json2nameValue($EVENT, &#039;z1Timer.Thursday_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1Timer.Friday:.* { json2nameValue($EVENT, &#039;z1Timer.Friday_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1Timer.Sunday:.* { json2nameValue($EVENT, &#039;z1Timer.Sunday_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1Timer.Saturday:.* { json2nameValue($EVENT, &#039;z1Timer.Saturday_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PrEnergyCountHc1:.* { json2nameValue($EVENT, &#039;PrEnergyCountHc1_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PrEnergyCountHwc1:.* { json2nameValue($EVENT, &#039;PrEnergyCountHwc1_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PrEnergySumHc1:.* { json2nameValue($EVENT, &#039;PrEnergySumHc1_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PrEnergySumHwc1:.* { json2nameValue($EVENT, &#039;PrEnergySumHwc1_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/FanHours:.* { json2nameValue($EVENT, &#039;FanHours_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/HcHours:.* { json2nameValue($EVENT, &#039;HcHours_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/HwcHours:.* { json2nameValue($EVENT, &#039;HwcHours_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/HcStarts:.* { json2nameValue($EVENT, &#039;HcStarts_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/HwcStarts:.* { json2nameValue($EVENT, &#039;HwcStarts_&#039;, $JSONMAP) }&lt;br /&gt;
attr vaillant setList HeizKennlinie:selectnumbers,0,.1,2,1,lin ebusd/700/Hc1HeatCurve/set $EVTPART1\&lt;br /&gt;
TagSolltemp:selectnumbers,15,1,25,1,lin ebusd/700/z1DayTemp/set $EVTPART1\&lt;br /&gt;
NachtSolltemp:selectnumbers,15,1,25,1,lin ebusd/700/z1NightTemp/set $EVTPART1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Definition eines DOIF-Devices zur Steuerung der Therme und Visualisierung der Daten. Es werden Readings und Befehle genutzt, die durch den MQTT2-Server der obigen Definition zur Verfügung gestellt werden. Einzelne Heizungswerte werden in bestimmten Intervallen über den publish-Befehl ausgelesen. Die Temperaturen der Zirkulation, des Vorlaufs und des Rücklaufs werden außerhalb der Therme mit 1-wire-Temperatursensoren über WLAN-ESP-Easy ausgelesen. Die Definition des Layouts über das Attribut uiTable ist unabhängig vom Auslesen der Werte, sie bezieht sich lediglich auf vorhandene Readings, die visualisiert werden sollen. Das Layout kann ebenso auf Readings aus anderen Devices der eigenen FHEM-Umgebung anpasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_vaillant DOIF ##{[+00:01];;foreach (qw(FanSpeed Flame PumpPower Storageloadpump PrimaryCircuitFlowrate FlowTempDesired PumpHours HcHours HcPumpStarts)) {fhem_set(&amp;quot;MQTT2_FHEM_Server publish ebusd/bai/$_/get&amp;quot;)}}\&lt;br /&gt;
\&lt;br /&gt;
{[+[1]:01];;foreach (qw(PrEnergySumHc1 PrEnergySumHwc1 HcHours HwcHours z1OpMode WaterPressure z1NightTemp z1DayTemp Hc1HeatCurve HwcLockTime HolidayStartPeriod HolidayEndPeriod)) {fhem_set(&amp;quot;MQTT2_FHEM_Server publish ebusd/bai/$_/get&amp;quot;)}\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
{[+00:00:30];;foreach (qw(Flame PrimaryCircuitFlowrate)) {fhem_set(&amp;quot;MQTT2_FHEM_Server publish ebusd/bai/$_/get&amp;quot;)}}\&lt;br /&gt;
\&lt;br /&gt;
{[00:01];;foreach (qw(FanHours HcStarts HwcStarts )) {fhem_set(&amp;quot;MQTT2_FHEM_Server publish ebusd/bai/$_/get&amp;quot;)}\&lt;br /&gt;
  set_Reading(&amp;quot;gesamt_hc&amp;quot;,int([?vaillant:PrEnergySumHc1_0_value]/10000)/10,0);;\&lt;br /&gt;
  set_Reading(&amp;quot;gesamt_hwc&amp;quot;,int([?vaillant:PrEnergySumHwc1_0_value]/10000)/10,0);;\&lt;br /&gt;
  set_Reading(&amp;quot;diff_hc&amp;quot;,0,1);;\&lt;br /&gt;
  set_Reading(&amp;quot;diff_hwc&amp;quot;,0,1);;\&lt;br /&gt;
  set_Reading(&amp;quot;diff_h&amp;quot;,0,1)\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
{if ([00:05|WE]) {fhem_set(&amp;quot;MQTT2_FHEM_Server publish ebusd/700/BankHolidayStartPeriod/set $mday.$month.$year&amp;quot;);;fhem_set(&amp;quot;MQTT2_FHEM_Server publish ebusd/700/BankHolidayEndPeriod/set $mday.$month.$year&amp;quot;)}}\&lt;br /&gt;
\&lt;br /&gt;
Timer {\&lt;br /&gt;
fhem_set &amp;quot;MQTT2_FHEM_Server publish ebusd/700/z1Timer.Monday/set 04:00;;09:00;;13:00;;22:00;;-:-;;-:-&amp;quot;\&lt;br /&gt;
fhem_set &amp;quot;MQTT2_FHEM_Server publish ebusd/700/z1Timer.Tuesday/set 04:00;;09:00;;13:00;;22:00;;-:-;;-:-&amp;quot;\&lt;br /&gt;
fhem_set &amp;quot;MQTT2_FHEM_Server publish ebusd/700/z1Timer.Wednesday/set 04:00;;09:00;;13:00;;22:00;;-:-;;-:-&amp;quot;\&lt;br /&gt;
fhem_set &amp;quot;MQTT2_FHEM_Server publish ebusd/700/z1Timer.Thursday/set 04:00;;09:00;;13:00;;22:00;;-:-;;-:-&amp;quot;\&lt;br /&gt;
fhem_set &amp;quot;MQTT2_FHEM_Server publish ebusd/700/z1Timer.Friday/set 04:00;;09:00;;13:00;;22:00;;-:-;;-:-&amp;quot;\&lt;br /&gt;
fhem_set &amp;quot;MQTT2_FHEM_Server publish ebusd/700/z1Timer.Sunday/set 05:00;;10:00;;12:00;;22:30;;-:-;;-:-&amp;quot;\&lt;br /&gt;
fhem_set &amp;quot;MQTT2_FHEM_Server publish ebusd/700/z1Timer.Saturday/set 05:00;;10:00;;12:00;;22:30;;-:-;;-:-&amp;quot;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
diff {\&lt;br /&gt;
 set_Reading(&amp;quot;diff_hc&amp;quot;,int(([vaillant:PrEnergySumHc1_0_value]/100000-get_Reading(&amp;quot;gesamt_hc&amp;quot;,0))*10)/10,1);;\&lt;br /&gt;
 set_Reading(&amp;quot;diff_hwc&amp;quot;,int(([vaillant:PrEnergySumHwc1_0_value]/100000-get_Reading(&amp;quot;gesamt_hwc&amp;quot;,0))*10)/10,1);;\&lt;br /&gt;
 set_Reading(&amp;quot;diff_h&amp;quot;,get_Reading(&amp;quot;diff_hc&amp;quot;)+get_Reading(&amp;quot;diff_hwc&amp;quot;),1);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
attr di_vaillant event-on-change-reading .*&lt;br /&gt;
attr di_vaillant room Ebus&lt;br /&gt;
attr di_vaillant uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
  $TABLE=&#039;text-align:center;;&#039;;;\&lt;br /&gt;
  $SHOWNODEVICELINE = &amp;quot;test9|Damian&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
icon_temp_ring(&amp;quot;temp_outside&amp;quot;,[vaillant:Aussentemp],-15,40,130)|\&lt;br /&gt;
icon_temp_mring(([vaillant:Flame] eq &amp;quot;off&amp;quot;?&amp;quot;sani_boiler_temp\@white&amp;quot;:&amp;quot;sani_boiler_temp\@Darkorange&amp;quot;),[vaillant:Vorlauf],15,70,130)|\&lt;br /&gt;
icon_temp_mring(([vaillant:Pumpenstatus] eq &amp;quot;4&amp;quot; ? &amp;quot;sani_buffer_temp_down\@Darkorange&amp;quot; : &amp;quot;sani_buffer_temp_down\@white&amp;quot;),[vaillant:WWSpeicher],15,70,130)|\&lt;br /&gt;
icon_uring(&amp;quot;0,0,1&amp;quot;,&amp;quot;weather_barometric_pressure&amp;quot;,[vaillant:Wasserdruck],0,3,undef,undef,&amp;quot;bar&amp;quot;,1,130,[(0.8,0,1,60,1.5,120,1.7,60,3,0)],&amp;quot;50,35&amp;quot;)|\&lt;br /&gt;
icon_ring(&amp;quot;sani_floor_heating_neutral&amp;quot;,[vaillant:HcHours_hoursum2_value],0,10000,120,0,&amp;quot;h&amp;quot;,0,130)|\&lt;br /&gt;
icon_ring(&amp;quot;sani_water_tap&amp;quot;,[vaillant:HwcHours_hoursum2_value],0,2000,120,0,&amp;quot;h&amp;quot;,0,130)|\&lt;br /&gt;
\&lt;br /&gt;
icon_ring(&amp;quot;time_graph&amp;quot;,[vaillant:HeizKennlinie],0.4,1,120,0,&amp;quot;HK&amp;quot;,1,130)|\&lt;br /&gt;
icon_temp_mring(&amp;quot;scene_day\@yellow&amp;quot;,[vaillant:TagSolltemp],undef,undef,130)|\&lt;br /&gt;
icon_temp_mring(&amp;quot;scene_night\@#3464eb&amp;quot;,[vaillant:NachtSolltemp],undef,undef,130)\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([vaillant:HeizKennlinie],&amp;quot;selectnumbers,0.4,.1,1,1,lin&amp;quot;,&amp;quot;set&amp;quot;)|widget([vaillant:TagSolltemp],&amp;quot;selectnumbers,15,1,25,1,lin&amp;quot;,&amp;quot;set&amp;quot;)|widget([vaillant:NachtSolltemp],&amp;quot;selectnumbers,15,1,25,1,lin&amp;quot;,&amp;quot;set&amp;quot;)&amp;lt;\&lt;br /&gt;
\&lt;br /&gt;
card([vaillant:Aussentemp:col],&amp;quot;Außentemperatur&amp;quot;,&amp;quot;temp_outside&amp;quot;,-15,35,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue)|\&lt;br /&gt;
card([vaillant:WWSpeicher:col],&amp;quot;WW-Speicher&amp;quot;,([vaillant:Pumpenstatus] eq &amp;quot;4&amp;quot; ? &amp;quot;sani_buffer_temp_down\@Darkorange&amp;quot; : &amp;quot;sani_buffer_temp_down\@white&amp;quot;),15,70,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue)|\&lt;br /&gt;
card([ESPEasy_ESP_Temp_Vorlauf:Temperature:col],&amp;quot;Vorlauf&amp;quot;,([vaillant:Pumpenstatus] eq &amp;quot;on&amp;quot; ? &amp;quot;sani_floor_heating\@Darkorange&amp;quot; : &amp;quot;sani_floor_heating_neutral\@white&amp;quot;),15,70,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue)|\&lt;br /&gt;
card([$SELF:diff_hc:col],&amp;quot;Energie Heizung&amp;quot;,&amp;quot;sani_floor_heating_neutral&amp;quot;,0,100,120,0,&amp;quot;kWh&amp;quot;,undef,1)\&lt;br /&gt;
card([vaillant:Umlaufmenge:col],&amp;quot;Umlaufmenge&amp;quot;,&amp;quot;sani_pump&amp;quot;,0,20,120,0,&amp;quot;l/min&amp;quot;)|\&lt;br /&gt;
card([ESPEasy_ESP_Temp_Zirkulation:Temperature:col],&amp;quot;Zirkulation&amp;quot;,([Zirk] eq &amp;quot;off&amp;quot;?&amp;quot;sani_pump\@white&amp;quot;:&amp;quot;sani_pump\@Darkorange&amp;quot;),15,70,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue)|\&lt;br /&gt;
card([ESPEasy_ESP_Temp_Keller_Ruecklauf:Temperature:col],&amp;quot;Rücklauf&amp;quot;,&amp;quot;sani_floor_heating_neutral\@wite&amp;quot;,15,70,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue)|\&lt;br /&gt;
card([$SELF:diff_hwc:col],&amp;quot;Energie Warmwasser&amp;quot;,&amp;quot;sani_water_tap&amp;quot;,0,15,120,0,&amp;quot;kWh&amp;quot;,undef,1)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:Di uiTable Heizung.png|600px|links]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;Visualisierung: &#039;&#039;&#039;Anwesenheitsstatus&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Die aktuelle Anwesenheit von Heimbewohnern wird visualisiert.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Zunächst wird mit Hilfe des Moduls [[FRITZBOX]] ein Device namens &#039;&#039;FritzBox&#039;&#039; erstellt. Dort werden die eingebuchten Smartphones der Bewohner mit Ihren MAC-Adressen in Readings abgelegt. Die folgende Definition wertet aus, ob die angegebenen MAC-Adressen als Readings vorhanden sind und erstellt für jeden Bewohner ein Reading mit den Zuständen on/off. Diese Readings werden dann über das Attribut uiTable visualisiert. Die anwesenden Personen werden farblich markiert. Die Namen der Personen sowie die MAC-Adressen sind fiktiv und müssen den eigenen Angaben entsprechend angepasst werden.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* [[FRITZBOX|FritzBox-Modul]]&lt;br /&gt;
* ui_Table Funktion [[DOIF/uiTable Schnelleinstieg#Icon-Darstellung mit Text mit Hilfe der Funktion icon_label|icon_label]]&lt;br /&gt;
*[[DOIF/uiTable Schnelleinstieg#uiTable-Templates|uiTable-Templates]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod myHome DOIF {\&lt;br /&gt;
 set_Reading_Begin;;\&lt;br /&gt;
  set_Reading_Update(&amp;quot;Ernie&amp;quot;,[FritzBox:mac_12_34_E0_00_CD_E4] ? &amp;quot;on&amp;quot;:&amp;quot;off&amp;quot;);;\&lt;br /&gt;
  set_Reading_Update(&amp;quot;Bert&amp;quot;, [FritzBox:mac_02_08_02_07_30_E3] ? &amp;quot;on&amp;quot;:&amp;quot;off&amp;quot;);;\&lt;br /&gt;
  set_Reading_Update(&amp;quot;Grobi&amp;quot;, [FritzBox:mac_00_08_01_0B_00_E7] ? &amp;quot;on&amp;quot;:&amp;quot;off&amp;quot;);; \&lt;br /&gt;
  set_Reading_Update(&amp;quot;Kermit&amp;quot;, [FritzBox:mac_01_30_A9_72_02_E3] ? &amp;quot;on&amp;quot;:&amp;quot;off&amp;quot;);; \&lt;br /&gt;
 set_Reading_End(1);;\&lt;br /&gt;
}&lt;br /&gt;
attr myHome checkReadingEvent 0&lt;br /&gt;
attr myHome uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
  $SHOWNOSTATE=1;;\&lt;br /&gt;
  $TC{0..4}=&amp;quot;align=&#039;center&#039;&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
## Template-Definition für die Visualisierung eines Bewohners mit Hilfe des Icons fa__508\&lt;br /&gt;
DEF TPL_person (icon_label([$SELF:$1] eq &amp;quot;on&amp;quot; ? &amp;quot;fa__508\@DarkOrange&amp;quot;:&amp;quot;fa__508&amp;quot;,&amp;quot;$1&amp;quot;,&amp;quot;#e67e00&amp;quot;,&amp;quot;white&amp;quot;,-10))\&lt;br /&gt;
\&lt;br /&gt;
## Darstellung der Bewohner mit Hilfe des obigen Templates\&lt;br /&gt;
TPL_person(Ernie)|TPL_person(Bert)|TPL_person(Grobi)|TPL_person(Kermit)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable myHome.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
=== Weitere Anwendungsbeispiele zur Automatisierung ===&lt;br /&gt;
* siehe [[DOIF/Automatisierung]]&lt;br /&gt;
&lt;br /&gt;
== Weiterführende Links ==&lt;br /&gt;
* Weitere Beispiele für Fortgeschrittene, siehe &amp;quot;[[DOIF/uiTable|uiTable mit FHEM-Widgets und Styles]]&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=DOIF/uiTable_Schnelleinstieg&amp;diff=37246</id>
		<title>DOIF/uiTable Schnelleinstieg</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=DOIF/uiTable_Schnelleinstieg&amp;diff=37246"/>
		<updated>2022-02-19T22:30:08Z</updated>

		<summary type="html">&lt;p&gt;Maista: Eine Klammer fehlte&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Datei:UiTable state screen.png|700px|rechts|Webansicht bestehend aus mehreren DOIF/uiTable-Definitionen]]&lt;br /&gt;
An dieser Stelle wird das DOIF-Web-Interface erklärt, welches über das DOIF-Attribut &#039;&#039;&#039;uiTable&#039;&#039;&#039; realisiert wurde. &lt;br /&gt;
&lt;br /&gt;
Abhängig von der Art der Funktion können in einer tabellarischen Darstellung FHEM-Geräte visualisiert und über die Web-Oberfläche bedient werden. Eventbasierte Änderungen visualisierter Readings werden unmittelbar in der Web-Ansicht aktualisiert. Eine erstellte Tabelle erscheint unterhalb der Statuszeile eines DOIF-Devices. Das uiTable-Attribut kann in bereits bestehenden DOIFs oder in funktionslosen DOIFs, wie in den unteren Beispielen, als reines WEB-Interface erstellt werden. In der Abbildung rechts ist ein Statusbildschirm aus vier Spalten mit mehreren DOIF/uiTable-Definitionen aufgebaut worden.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Darstellungsmöglichkeiten werden anhand von Beispielen insb. mit Hilfe bereits im DOIF-Modul vordefinierter uiTable-Funktionen aufgezeigt. Diese Perlfunktionen sind in einem eigenen Package namens &#039;ui_Table&#039; definiert worden. Mit Hilfe dieser Funktionen lassen sich recht einfach, ohne tiefere HTML/CSS-Kenntnisse, eigene Übersichten definieren. Im Anschluss werden typische &#039;&#039;&#039;[[DOIF/uiTable Schnelleinstieg#Anwendungsbeispiele|Anwendungsbeispiele]]&#039;&#039;&#039; aufgezeigt.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Beispieldefinitionen arbeiten mit konkreten Geräten und Readings, sie können als RAW-Definition ins eigene System übernommen werden, dazu müssen die Gerätenamen, Readings, ggf. auch Icons den existierenden Namen des eigenen Systems angepasst werden. Zum Ausprobieren der Beispiele können statt echter Geräte auch Dummys benutzt werden. &lt;br /&gt;
&lt;br /&gt;
Es gibt im Perl-Modus des DOIF-Moduls ebenfalls das Attribut &#039;&#039;&#039;uiState&#039;&#039;&#039;, welches die gleiche Syntax wie uiTable nutzt. Die definierte Tabelle erscheint im Gegensatz zu uiTable jedoch im Status des DOIF-Devices. uiState und uiTable können gleichzeitig in einem DOIF-Device definiert werden.  &lt;br /&gt;
&lt;br /&gt;
== Aufbau des uiTable-Attributs ==&lt;br /&gt;
Im uiTable-Attribut wird in erster Linie die zu visualisierende Tabelle definiert. Optional können zuvor ein Perlblock sowie Templates definiert werden.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;Aufbau des Attributs&#039;&#039;&#039;&lt;br /&gt;
* das uiTable-Attribut besteht aus drei Bereichen:&lt;br /&gt;
* [[DOIF/uiTable Schnelleinstieg#Der Perlblock|Perlblock]]&lt;br /&gt;
* [[DOIF/uiTable Schnelleinstieg#uiTable-Templates|Templates-Definitionen]] &lt;br /&gt;
* [[DOIF/uiTable Schnelleinstieg#Die Tabellendefinition|Tabellendefinition]]&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;Aufbaustruktur&#039;&#039;&#039; &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
&amp;lt;Perlblock, optional&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;Templates-Definitionen, optional&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;Tabellendefinition&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Der Perlblock ===&lt;br /&gt;
Der Perlblock dient dazu, das Layout der Tabelle zu beeinflussen sowie eigene uiTable-Funktionen zu definieren. Hier wird insb. das Package definiert, welches für die Tabellendefinition gilt. Ebenfalls können CSS-Variablen sowie Steuerungsattribute gesetzt werden. Der Perlblock beginnt und endet mit einer geschweiften Klammer.&lt;br /&gt;
&lt;br /&gt;
==== CSS-Variablen und Steuerungsattribute ====&lt;br /&gt;
Mit Hilfe von CSS-Variablen kann das Layout der Tabelle beeinflusst werden. Die Steuerungsattribute beeinflussen die Statuszeile sowie die Detailansicht des DOIF-Moduls.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;CSS-Variablen und Steuerungsattribute&#039;&#039;&#039;&lt;br /&gt;
*Das Layout der gesamten Tabelle wird beeinflusst über die Variablendefinition: &#039;&#039;&#039;$TABLE=&amp;quot;&amp;lt;CSS-Attribute der Tabelle&amp;gt;&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
*Spaltenformatierungen werden beeinflusst mit Hilfe der Variablendefinition: &#039;&#039;&#039;$TC{&amp;lt;Zellenbereich für Spalten&amp;gt;}=&amp;quot;&amp;lt;CSS-Attribute der Spalten&amp;gt;&amp;quot;&#039;&#039;&#039; &lt;br /&gt;
*Zeilenformatierungen werden beeinflusst mit Hilfe der Variablendefinition: &#039;&#039;&#039;$TR{Zeilenbereich}=&amp;quot;&amp;lt;CSS-Attribute der Zeilen&amp;gt;&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
*einzelne Zellen werden beeinflusst mit Hilfe der Variablen: &#039;&#039;&#039;$TD{&amp;lt;Zellenbereich für Zeilen&amp;gt;}{&amp;lt;Zellenbereich für Spalten&amp;gt;}=&amp;quot;&amp;lt;CSS-Attribute der Zellen&amp;gt;&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
*für Zellen-, Spalten- und Zeilen-Bereich gilt: &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;&amp;lt;kommagetrennte Aufzählung&amp;gt;&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;&amp;lt;Bereich von..bis&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
*Der Status in der Statuszeile des DOIFs wird ausgeblendet mit &#039;&#039;&#039;$SHOWNOSTATE=1&#039;&#039;&#039;&lt;br /&gt;
*Die Gerätezeile des DOIFs wird ausgeblendet mit &#039;&#039;&#039;$SHOWNODEVICELINE = &amp;quot;&amp;lt;regex room&amp;gt;&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
*Die Tabelle des DOIFs wird ausgeblendet mit &#039;&#039;&#039;$SHOWNOUITABLE = &amp;quot;&amp;lt;regex room&amp;gt;&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
*Die Detailansicht wird umorganisiert mit &#039;&#039;&#039;$ATTRIBUTESFIRST=1&#039;&#039;&#039;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;Bespieldefinition&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_bsp_layout DOIF ##&lt;br /&gt;
attr di_bsp_layout uiTable { ## Beginn des Perlblocks\&lt;br /&gt;
## CSS-Variablen\&lt;br /&gt;
\&lt;br /&gt;
## Die Tabelle soll ein Hintergrundbild der Größe 300x300 Pixel haben\&lt;br /&gt;
$TABLE = &amp;quot;width:300px;; height:300px;; background-image:url(/fhem/www/pgm2/images/Grundriss.png);; background-size: 300px 300px;;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
## die Zelle der ersten Zeile und der ersten Spalte soll rechts eine Rahmenlinie haben\&lt;br /&gt;
$TD{0}{0} = &amp;quot;style=&#039;border-right-style:solid;; border-right-width:10px&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
## Die erste Zeile soll aus der Klasse &#039;odd&#039; sein und fett-Schrift haben\&lt;br /&gt;
$TR{0} = &amp;quot;class=&#039;odd&#039; style=&#039;font-weight:bold&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
## die Spalten 2 bis 6 sollen zentriert sein\&lt;br /&gt;
$TC{1..5} = &amp;quot;align=&#039;center&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
## die Spalten 2, 4 und 5 sollen zentriert sein\&lt;br /&gt;
$TC{1,3,5} = &amp;quot;align=&#039;center&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
## die letzte Spalte der Tabelle soll fett sein\&lt;br /&gt;
$TC{last} = &amp;quot;style=&#039;font-weight:bold&#039;&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
\## Steuerungsattribute\&lt;br /&gt;
\&lt;br /&gt;
\## Ausblenden des Status in der Statuszeile\&lt;br /&gt;
$SHOWNOSTATE=1;;\&lt;br /&gt;
\&lt;br /&gt;
## Die Gerätezeile wird ausgeblendet in allen Räumen\&lt;br /&gt;
$SHOWNODEVICELINE = &amp;quot;.*&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
## Die Tabelle wird im Raum info ausgeblendet\&lt;br /&gt;
$SHOWNOUITABLE = &amp;quot;^info$&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
## Die Detailansicht wird umorganisiert, hilfreich beim Editieren längerer uiTable-Definitionen\&lt;br /&gt;
$ATTRIBUTESFIRST = 1;;\&lt;br /&gt;
} ## Ende des Perlblocks&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Die Tabellendefinition ===&lt;br /&gt;
==== Einfache Tabellendefinition ohne Funktionen ====&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;Tabellendefinition&#039;&#039;&#039;&lt;br /&gt;
* eine Tabelle wird aus Zellen zusammengebaut&lt;br /&gt;
* mehrere Zellen werden mit &amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; von einander getrennt, sie bilden eine Tabellenzeile&lt;br /&gt;
* eine neue Tabellenzeile beginnt mit einer neuen Zeile in der Tabellendefinition&lt;br /&gt;
* eine Tabellenzeile kann auch in mehreren Zeilen definiert werden, diese müssen dann mit &amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; enden&lt;br /&gt;
* Texte werden in Anführungszeichen angegeben&lt;br /&gt;
* Readings werden in der Form [&amp;lt;device&amp;gt;:&amp;lt;reading&amp;gt;] angegeben&lt;br /&gt;
* Kommentare beginnen mit ## und enden mit Zeilenende&lt;br /&gt;
* Events eines definierten Readings, führen sofort zu Aktualisierung seines Inhalts in der visualisierten Tabelle&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod ui_Table_definition DOIF ##&lt;br /&gt;
attr ui_Table_definition uiTable { ## Perlblock für globale Tabellendefinitionen\&lt;br /&gt;
 \&lt;br /&gt;
 $TC{1..2}=&amp;quot;align=&#039;center&#039;&amp;quot; ## zentrierte Ausrichtung der zweiten und dritten Spalte\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Warmwasser&amp;quot;|&amp;quot;Vorlauf&amp;quot;|&amp;quot;Rücklauf&amp;quot;   ## erste Tabellenzeile\&lt;br /&gt;
									## zweite Tabellenzeile\&lt;br /&gt;
[T_Warmwasserspeicher:temperature]| ## Zeile wird fortgesetzt, da sie mit | endet\&lt;br /&gt;
[T_Vorlauf:temperature]|            ## Zeile wird fortgesetzt, da sie mit | endet\&lt;br /&gt;
[T_Ruecklauf:temperature]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable Definition.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
==== Tabellendefinition mit Berechnungen ====&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;Zellenauswertung&#039;&#039;&#039;&lt;br /&gt;
* jede Zelle der Tabelle wird über Perl ausgewertet&lt;br /&gt;
* Readingangaben der Form [&amp;lt;device&amp;gt;:&amp;lt;reading&amp;gt;] werden in eine Perlfunktion übersetzt&lt;br /&gt;
* das Ergebnis des ausgewerteten Perlausdrucks wird ausgegeben&lt;br /&gt;
* in einer Zelle können beliebige Perlfunktionen genutzt werden&lt;br /&gt;
* Texte oder Funktionen können mit Punkt aneinander gehängt werden&lt;br /&gt;
* mit Komma werden Texte oder Werte untereinander dargestellt&lt;br /&gt;
* wird eine Zeile mit &amp;lt; abgeschlossen, so wird die aktuelle Tabelle abgeschlossen, die nächste Zeile beginnt in einer neuen Tabelle&lt;br /&gt;
* in einer Berechnung sollte ein Trigger in Form einer Readingangabe [&amp;lt;device&amp;gt;:&amp;lt;reading&amp;gt;] vorkommen, sonst wäre das Ergebnis statisch und würde sich nicht ändern &lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_calc DOIF ##&lt;br /&gt;
attr di_uiTable_calc uiTable ## Tabellendefinition\&lt;br /&gt;
&amp;quot;Differenz&amp;quot;|[T_Ruecklauf:temperature]-[T_Vorlauf:temperature]\&lt;br /&gt;
&amp;quot;Minimum&amp;quot;|minNum([TH_WZ_HM:measured-temp],[TH_Keller_HM:measured-temp])\&lt;br /&gt;
&amp;quot;Durchschnitt&amp;quot;|([T_Ruecklauf:temperature]+[T_Vorlauf:temperature])/2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable calc.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
== Vordefinierte uiTable-Funktionen ==&lt;br /&gt;
Typische Widgets bzw. Styles wurden als Perl-Funktionen im package ui_Table für eine einfache Tabellendefinition programmiert. Im folgenden wird näher auf die einzelnen uiTable-Funktionen eingegangen.&lt;br /&gt;
&lt;br /&gt;
=== FHEM-Widgets mit der Funktion &#039;&#039;&#039;widget&#039;&#039;&#039; ===&lt;br /&gt;
Alle in FHEM vorhanden Widgets können mit Hilfe der Perlfunktion &#039;&#039;&#039;widget&#039;&#039;&#039; genutzt werden. Bei häufiger Nutzung eines bestimmten Widgets bietet sich alternativ die Definition einer uiTable-Funktion (Typ 3) mit dem jeweiligen Widget an, siehe: [[DOIF/uiTable Schnelleinstieg#Eigene uiTable-Funktionen programmieren|uiTable-Funktion]]&lt;br /&gt;
{{Randnotiz|RNText=Funktion &#039;&#039;&#039;widget&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
widget(&amp;lt;Reading&amp;gt;,$fhem_widget,$set)&lt;br /&gt;
&lt;br /&gt;
Reading      # [&amp;lt;device&amp;gt;:&amp;lt;reading&amp;gt;]&lt;br /&gt;
$fhem_widget # Angabe des FHEM-Widgets&lt;br /&gt;
$set         # optional, undef zum Setzen beliebiger Readings (entspricht setreading), &amp;quot;set&amp;quot; wenn das Reading per set-Befehl gesetzt wird (siehe Attribut ReadingList), &amp;quot;set &amp;lt;Befehl&amp;gt;&amp;quot;, wenn sich der Befehl vom Reading unterscheidet, default undef&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* [[FHEMWEB/Widgets|Fhem-Widgets]]&lt;br /&gt;
* Fhem-Widgets als [[DOIF/uiTable Schnelleinstieg#Eigene uiTable-Funktionen programmieren|uiTable-Funktion]]&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_widget DOIF ##&lt;br /&gt;
attr di_uiTable_widget uiTable ## FHEM-Widgets mit Hilfe der WID-Funktion\&lt;br /&gt;
{package ui_Table}\&lt;br /&gt;
&amp;quot;Widget&amp;quot;\&lt;br /&gt;
&amp;quot;Select&amp;quot;| widget([uhr:wochentag],&amp;quot;select,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag,Sonntag&amp;quot;)\&lt;br /&gt;
&amp;quot;Selectnumbers&amp;quot;| widget([motor:spannung],&amp;quot;selectnumbers,0,0.5,12,1,lin&amp;quot;)\&lt;br /&gt;
&amp;quot;Slider&amp;quot;| widget([bla:wert],&amp;quot;slider,0,5,100,1&amp;quot;)\&lt;br /&gt;
&amp;quot;Colorpicker RGB&amp;quot;| widget([Lampe:farbe],&amp;quot;colorpicker,RGB&amp;quot;)\&lt;br /&gt;
&amp;quot;Colorpicker HSV&amp;quot;| widget([Lampe:farbe],&amp;quot;colorpicker,HSV&amp;quot;)\&lt;br /&gt;
&amp;quot;Colorpicker CT&amp;quot;| widget([Lampe:waerme],&amp;quot;colorpicker,CT,2000,10,6500&amp;quot;)\&lt;br /&gt;
&amp;quot;Colorpicker HUE&amp;quot;| widget([Lampe:farbe],&amp;quot;colorpicker,HUE,0,1,359&amp;quot;)\&lt;br /&gt;
&amp;quot;Colorpicker BRI&amp;quot;| widget([Lampe:helligkeit],&amp;quot;colorpicker,BRI,0,1,100&amp;quot;)\&lt;br /&gt;
&amp;quot;Time&amp;quot;| widget([start:zeit],&amp;quot;time&amp;quot;)\&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable WID.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
=== SVG-uiTable-Funktionen ===&lt;br /&gt;
SVG-uiTable-Funktionen sind skalierbare Widgets, die auf SVG-Elementen basieren. Bei allen SVG-Funktionen für Temperatur bzw. Feuchtigkeit wird die Einfärbung abhängig vom Temperatur- bzw. Feuchtigkeitswert mit Hilfe einer Zuordnungsfunktion bestimmt.&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;ring&#039;&#039;&#039;-Funktionen ====&lt;br /&gt;
===== Farbskalierte Temperaturanzeige mit Hilfe der SVG-Funktionen &#039;&#039;&#039;temp_ring/temp_mring&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe der dargestellten Temperatur ist abhängig vom Temperaturwert. Die Helligkeit der Farbgebung ist einstellbar. Bei der &#039;&#039;&#039;temp_mring&#039;&#039;&#039;-SVG-Funktion wird der Ring einfarbig dargestellt.&lt;br /&gt;
&lt;br /&gt;
Farbskalierung der &#039;&#039;&#039;temp_ring&#039;&#039;&#039;-SVG-Funktion:&lt;br /&gt;
[[Datei:Farbskalierung temp_ring_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
Farbskalierung der &#039;&#039;&#039;temp_mring&#039;&#039;&#039;-SVG-Funktion:&lt;br /&gt;
[[Datei:Farbskalierung temp_mring_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;temp_ring/temp_mring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
temp_ring/temp_mring ($temp_value,$temp_min,$temp_max,$sizeHalf, $lightring,$lightnumber,$decFont) &lt;br /&gt;
&lt;br /&gt;
$temp_value  # Temperatur&lt;br /&gt;
$temp_min,   # minimale Temperatur, optional, default=-20&lt;br /&gt;
$temp_max,   # maximale Temperatur, optional, default=60&lt;br /&gt;
$sizeHalf    # &amp;quot;&amp;lt;size&amp;gt;,&amp;lt;half ring&amp;gt;&amp;quot; size: Größe der Grafik, optional, default = 80, half ring: 1 für Halbring&lt;br /&gt;
$lightring,  # Helligkeit des Ringes (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFont     # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_temp_ring DOIF ##&lt;br /&gt;
attr di_temp_ring uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;außen (standard)&amp;quot;|temp_ring([Aussensensor:temperature])\&lt;br /&gt;
&amp;quot;Warmwasser (größer,aufgehellt,Normalschrift)&amp;quot; |temp_mring([vaillant:WWSpeicher],15,70,110,90,100,&amp;quot;1,font-weight:normal&amp;quot;)\&lt;br /&gt;
&amp;quot;Vorlauf (größer)&amp;quot;| temp_mring([ESPEasy_ESP_Temp_Vorlauf:Temperature],15,45,100)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:temp_ring_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Feuchtigkeitsanzeige mit Hilfe der SVG-Funktionen &#039;&#039;&#039;hum_ring/hum_mring&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe der dargestellten Feuchtigkeit ist abhängig vom Feuchtigkeitswert. Die Helligkeit der Farbgebung ist einstellbar. Bei der &#039;&#039;&#039;hum_mring&#039;&#039;&#039;-SVG-Funktion wird der Ring einfarbig dargestellt.&lt;br /&gt;
&lt;br /&gt;
Farbskalierung der &#039;&#039;&#039;hum_ring&#039;&#039;&#039;-SVG-Funktion: &lt;br /&gt;
[[Datei:Farbskalierung hum_ring_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
Farbskalierung der &#039;&#039;&#039;hum_mring&#039;&#039;&#039;-SVG-Funktion:&lt;br /&gt;
[[Datei:Farbskalierung hum_mring_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;hum_ring/hum_mring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
hum_ring/hum_mring ($hum_value,$sizeHalf,$lightring,$lightnumber,$decFont) &lt;br /&gt;
$hum_value   # Feuchtigkeit&lt;br /&gt;
$sizeHalf  # &amp;quot;&amp;lt;size&amp;gt;,&amp;lt;half ring&amp;gt;&amp;quot; size: Größe der Grafik, optional, default = 80, half ring: 1 für Halbring&lt;br /&gt;
$lightring   # Helligkeit des Ringes (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFont     # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_hum_ring DOIF ##&lt;br /&gt;
attr di_hum_ring room test2&lt;br /&gt;
attr di_hum_ring uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;klein ohne Farbverlauf&amp;quot;|hum_mring([Aussensensor:humidity],60)\&lt;br /&gt;
&amp;quot;normal groß mit Farbverlauf&amp;quot;|hum_ring([Aussensensor:humidity])\&lt;br /&gt;
&amp;quot;groß ohne Farbverlauf aufgehellt&amp;quot;|hum_mring([Aussensensor:humidity],100,80)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:hum_ring_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige eines Zahlenwertes mit Hilfe der universellen SVG-Funktion &#039;&#039;&#039;ring&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe des dargestellten Wertes kann abhängig vom Wert bestimmt werden. Dabei wird die Farbe mit Anleihen aus dem [https://de.wikipedia.org/wiki/HSV-Farbraum HSV-Farbraum] bestimmt. Dieser Farbraum benötigt eigentlich drei Werte, wobei die erste den Farbton (hue) bestimmt; hier wird nur dieser Wert verwendet (Sättigung und Hellwert sind nicht einstellbar). Der Farbton geht von rot (hue-Wert = 0) über gelb (hue-Wert = 60), dann grün (hue-Wert = 120) und blau (hue-Wert = 240) zurück zu rot (hue-Wert = 360), siehe dazu auch die [https://de.wikipedia.org/wiki/HSV-Farbraum#/media/Datei:HueScale.svg Farbtontafel] auf der Wikipedia-Seite.&lt;br /&gt;
Die unten $colorRef genannte Funktion kann zum Beispiel in der Tabelle selbst definiert werden, beispielsweise kann man in dem device &amp;amp;onoff_hue verwenden, wenn man es vorab definiert (siehe [https://forum.fhem.de/index.php/topic,120088.msg1204341.html#msg1204341 Link zum Forum]):&amp;lt;blockquote&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
attr &amp;lt;ui device Name&amp;gt; {&lt;br /&gt;
  package ui_Table;&lt;br /&gt;
    sub onoff_hue {&lt;br /&gt;
    my($irgendeinVariablenname)=@_;&lt;br /&gt;
    return ($irgendeinVariablenname == 0 ? 240 : 0); &lt;br /&gt;
  }&lt;br /&gt;
## Tabellendefinition&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;/blockquote&amp;gt;{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;ring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
ring ($value,$min,$max,$minColor,$maxColor,$unit, $sizeHalf,$colorRef,$decFont,$model,$lightness)&lt;br /&gt;
&lt;br /&gt;
$value     # darzustellender Wert&lt;br /&gt;
$min       # minimaler Wert, optional, default=0&lt;br /&gt;
$max       # maximaler Wert, optional, default=100&lt;br /&gt;
$minColor  # Farbe (hue: 0-360) des kleinsten Wertes, optional, default = undef&lt;br /&gt;
$maxColor  # Farbe (hue: 0-360) des maximalen Wertes, optional, default = undef&lt;br /&gt;
$unit      # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$sizeHalf  # &amp;quot;&amp;lt;size&amp;gt;,&amp;lt;half ring&amp;gt;&amp;quot; size: Größe der Grafik, optional, default = 100, half ring: 1 für Halbring&lt;br /&gt;
$colorRef  # Referenz auf eine Funktion, die zu einem Wert einen Farbwert (hue: 0-360) bestimmt, oder eine Referenz auf eine Arrayliste mit Grenzwerten und Farben, optional, default = undef&lt;br /&gt;
$decFont   # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$model      # &#039;&amp;lt;Farbverlauf&amp;gt;,&amp;lt;Min/Max&amp;gt;,&amp;lt;Innenring&amp;gt;,&amp;lt;Zeigerstärke&amp;gt;,&amp;lt;Modus&amp;gt;&#039;,&lt;br /&gt;
            #   Farbverlauf: 1 für monochrom, &lt;br /&gt;
            #   Min/Max: Style-SVG-Attribute oder 1 zum Anzeigen der Min-/Maxwerte,&lt;br /&gt;
            #   Innenring: Style-SVG-Attribute oder 1 zum Anzeigen des Innenringes, Zeigerstärke: in Pixel,&lt;br /&gt;
            #   Zeigerstärke: Breite des Zeigers,&lt;br /&gt;
            #   Modus: 0 Standard Min-Max, 1 Min-Null-Max, 2 Null-Min/Max,&lt;br /&gt;
            #   alle Parameter sind optional, default keine Angaben: &#039;,,,,,&#039;&lt;br /&gt;
$lightness  # Helligkeit einzelner Elemente (0-100) &amp;quot;&amp;lt;ring&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;minMax&amp;gt;,&amp;lt;unit&amp;gt;,&amp;lt;value&amp;gt;&amp;quot;, optional, default: &amp;quot;50,50,50,40,50&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird &#039;&#039;&#039;$colorFunc&#039;&#039;&#039; nicht angegeben, so wird der Farbwert zwischen &#039;&#039;&#039;$minColor&#039;&#039;&#039; und &#039;&#039;&#039;$maxColor&#039;&#039;&#039; linear interpoliert&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_ring DOIF (1)&lt;br /&gt;
attr di_ring room test20,test5&lt;br /&gt;
attr di_ring uiTable {package ui_Table;; \&lt;br /&gt;
 $SHOWNOSTATE=1}\&lt;br /&gt;
## von 0 bis 20 in Farben von grün (hue:120) bis rot (hue:0)\&lt;br /&gt;
&amp;quot;Umlaufmenge&amp;quot;|ring([heating:pump],0,20,120,0,&amp;quot;l/min&amp;quot;,100)\&lt;br /&gt;
\&lt;br /&gt;
## von 0 bis 3 in Farben von rot (hue:0) bis türkis (hue:180), eine Nachkommastelle, Schriftgröße 170%\&lt;br /&gt;
## Innenring mit Min-, Max-Beschriftung\&lt;br /&gt;
&amp;quot;Wasserdruck&amp;quot;|ring([heating:pressure],0,3,0,180,&amp;quot;bar&amp;quot;,100,undef,&amp;quot;1,font-size:170%,fill:silver;;font-size:50%&amp;quot;,&amp;quot;0,1,1&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Temperaturdarstellung, entspricht dem Funktionsaufruf:\&lt;br /&gt;
## temp_ring ([outdoor:temperature],-20,60,100,&amp;quot;1,font-weight:normal;;font-size:140%&amp;quot;)\&lt;br /&gt;
## Eine Nachkommastelle, Normalschrift, Schriftgröße 140%\&lt;br /&gt;
&amp;quot;Temperatur&amp;quot;|ring([outdoor:temperature,-20,60,undef,undef,&amp;quot;°C&amp;quot;,100,\&amp;amp;temp_hue,&amp;quot;1,font-weight:normal;;font-size:140%&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Lufdruck als Halbring\&lt;br /&gt;
&amp;quot;Luftdruck&amp;quot;|ring([weather:barometer],970,1045,30,90,&amp;quot;hPa&amp;quot;,&amp;quot;100,1&amp;quot;,undef,0)\&lt;br /&gt;
\&lt;br /&gt;
## Co2 als Halbring, Farbgebung als Array mit drei Bereichen, Innenring mit Zeiger\&lt;br /&gt;
&amp;quot;Co2&amp;quot;|ring([livingroom:co2],400,1200,undef,undef,&#039;ppm&#039;,&amp;quot;100,1&amp;quot;,[(600,120,1000,60,1200,0)],0,&#039;0,0,1,5&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:ring_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Temperatur- und Feuchtigkeitsanzeige mit Hilfe der SVG-Funktion &#039;&#039;&#039;temp_hum_ring&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe ist jeweils abhängig vom dargestellten Temperatur- bzw. Feuchtigkeitswert. Die Helligkeit der Farbgebung ist einstellbar:&lt;br /&gt;
[[Datei:Farbskalierung temp_hum_ring_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;temp_hum_ring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
temp_hum_ring ($temp_value,$hum_value,$temp_min,$temp_max,$size, $lightring,$lightnumber,$decFontTemp,$decFontHum)&lt;br /&gt;
&lt;br /&gt;
$temp_value # Temperatur&lt;br /&gt;
$hum_value  # Feuchtigkeit&lt;br /&gt;
$temp_min   # minimale Temperatur, optional, default=-20&lt;br /&gt;
$temp_max   # maximale Temperatur, optional, default=60&lt;br /&gt;
$size       # Größe der Grafik, optional, default=90&lt;br /&gt;
$lightring   # Helligkeit des Ringes (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFontTemp # Temperatur: &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$decFontHum  # Feuchtigkeit: &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_temp_hum_ring DOIF ##&lt;br /&gt;
attr di_temp_hum_ring uiTable {package ui_Table}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;klein&amp;quot;|temp_hum_ring([Aussensensor:temperature],[Aussensensor:humidity],undef,undef,60)\&lt;br /&gt;
&amp;quot;normal&amp;quot;|temp_hum_ring([Aussensensor:temperature],[Aussensensor:humidity])\&lt;br /&gt;
&amp;quot;größer, aufgehellt&amp;quot;|temp_hum_ring([Aussensensor:temperature],[Aussensensor:humidity],undef,undef,100,undef,80)\&lt;br /&gt;
&amp;quot;größer, Ring aufgehellt, Normalschrift&amp;quot;|temp_hum_ring([Aussensensor:temperature],[Aussensensor:humidity],undef,undef,100,80,50,&amp;quot;1,font-weight:normal&amp;quot;,&amp;quot;0,font-weight:normal&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:temp_hum_ring_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige von zwei Temperaturwerten mit Hilfe der SVG-Funktion &#039;&#039;&#039;temp_temp_ring&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe ist jeweils abhängig vom dargestellten Temperaturwert. Die Helligkeit der Farbgebung ist einstellbar:&lt;br /&gt;
[[Datei:Farbskalierung temp_temp_ring_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;temp_temp_ring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
temp_temp_ring ($temp1_value,$temp2_value,$temp_min,$temp_max,$size, $lightring,$lightnumber,$decFontTemp1,$decFontTemp2)&lt;br /&gt;
&lt;br /&gt;
$temp1_value # erster Temperaturwert&lt;br /&gt;
$temp2_value # zweiter Temperaturwert&lt;br /&gt;
$temp_min    # minimale Temperatur, optional, default=-20&lt;br /&gt;
$temp_max    # maximale Temperatur, optional, default=60&lt;br /&gt;
$size        # Größe der Grafik, optional, default=90&lt;br /&gt;
$lightring   # Helligkeit des Ringes (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFontTemp1 # Temperatur1: &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$decFontTemp2 # Temperatur2: &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_temp_temp_ring DOIF ##&lt;br /&gt;
attr di_temp_temp_ring uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;klein, Ring augehellt&amp;quot;|temp_temp_ring([Vorlauf:Temperature],[Ruecklauf:Temperature],15,60,60,80,50)\&lt;br /&gt;
&amp;quot;normal&amp;quot;|temp_temp_ring([Vorlauf:Temperature],[Ruecklauf:Temperature],15,60)\&lt;br /&gt;
&amp;quot;groß, Zahlen aufgehellt&amp;quot;|temp_temp_ring([Vorlauf:Temperature],[Ruecklauf:Temperature],15,60,100,undef,80)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:temp_hum_temp_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige von zwei Zahlenwerten mit Hilfe der universellen SVG-Funktion &#039;&#039;&#039;ring2&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe der dargestellten Werte kann abhängig vom Wert bestimmt werden.&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;ring2&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
ring2 ($value1,$min1,$max1,$minColor1,$maxColor1,$unit1,$size,$colorFunc1,$decFont1,&lt;br /&gt;
       $value2,$min2,$max2,$minColor2,$maxColor2,$unit2,$colorFunc2,$decFont2,&lt;br /&gt;
       $lightness,$icon,$model)&lt;br /&gt;
&lt;br /&gt;
$value1     # darzustellender Wert1&lt;br /&gt;
$min1       # minimaler Wert, optional, default=0&lt;br /&gt;
$max1       # maximaler Wert, optional, default=100&lt;br /&gt;
$minColor1  # Farbe (hue: 0-360) des kleinsten Wertes, optional, default = undef&lt;br /&gt;
$maxColor1  # Farbe (hue: 0-360) des maximalen Wertes, optional, default = undef&lt;br /&gt;
$unit1      # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$size       # Größe der Grafik, optional, default = 100&lt;br /&gt;
$colorFunc1 # Funktion, die zu einem Wert einen Farbwert (hue: 0-360) bestimmt, optional, default = undef&lt;br /&gt;
$decFont1   # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$value2     # darzustellender Wert2&lt;br /&gt;
...&lt;br /&gt;
$decFont2   # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$lightness  # Helligkeit einzelner Elemente (0-100) &amp;quot;&amp;lt;ring&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;minMax&amp;gt;,&amp;lt;unit&amp;gt;,&amp;lt;value&amp;gt;,&amp;lt;icon&amp;gt;&amp;quot;, optional, default: &amp;quot;50,50,50,40,50,40&amp;quot;&lt;br /&gt;
$model      # &#039;&amp;lt;color gradient&amp;gt;,&amp;lt;min/max&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;pointer&amp;gt;,&amp;lt;mode&amp;gt;&#039;,&lt;br /&gt;
            # &amp;lt;color gradient&amp;gt;: 1 für monochrom&lt;br /&gt;
            # &amp;lt;min/max&amp;gt;: Style-SVG-Attribute oder 1 zum Anzeigen der Min-/Maxwerte&lt;br /&gt;
            # &amp;lt;inner ring&amp;gt;: Style-SVG-Attribute oder 1 zum Anzeigen des Innenringes&lt;br /&gt;
            # &amp;lt;pointer&amp;gt;: Breite des Zeigers in Pixel&lt;br /&gt;
            # &amp;lt;mode&amp;gt;: 0 Standard Min. - Max., 1 negativ - Null - positiv, 2 Null - negativ/positiv&lt;br /&gt;
            # alle Parameter sind optional, default keine Angaben: &#039;,,,,,,&#039;&lt;br /&gt;
&lt;br /&gt;
Argumente für den zweiten Wert entsprechend den Argumenten des ersten Wertes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird &#039;&#039;&#039;$colorFunc...&#039;&#039;&#039; nicht angegeben, so wird der Farbwert zwischen &#039;&#039;&#039;$minColor...&#039;&#039;&#039; und &#039;&#039;&#039;$maxColor...&#039;&#039;&#039; linear interpoliert&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_ring2 DOIF ##&lt;br /&gt;
attr di_ring2 uiTable {package ui_Table;;}\&lt;br /&gt;
## Leistungsaufnahme von 0 kW bis 3,6 kW in Farben von grün (hue:120) bis rot (hue:0)\&lt;br /&gt;
## Kapazität von 0 % bis 100 % V in Farben von rot (hue:0) bis grün (hue:120)\&lt;br /&gt;
&amp;quot;Wallbox&amp;quot;| ring2([tesla:Leistung],0,3.6,120,0,&amp;quot;kW&amp;quot;,undef,undef,&amp;quot;1,font-weight:normal&amp;quot;,[tesla:Kapazitaet],0,100,0,120,&amp;quot;%&amp;quot;,undef,&amp;quot;0,font-weight:normal&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Stromstärke von 0 A bis 2 A in Farben von grün (hue:120) bis rot (hue:0)\&lt;br /&gt;
## Spannung von 1 V bis 1.5 V in Farben von rot (hue:0) bis grün (hue:120)\&lt;br /&gt;
## 3 Nachkommastellen, Normalschrift, Schriftgröße 80%  \&lt;br /&gt;
&amp;quot;Akku&amp;quot;| ring2([akku:Strom],0,2,120,0,&amp;quot;A&amp;quot;,undef,undef,&amp;quot;3,font-weight:normal;;font-size:80%&amp;quot;,[akku:Spannung],1,1.5,0,120,&amp;quot;V&amp;quot;,undef,&amp;quot;3,font-weight:normal;;font-size:80%&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:ring2_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition Innenring, Farb-Array, Ringmodi&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_solar DOIF {}&lt;br /&gt;
attr di_solar uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;Farb-Array, ringMode 1&amp;quot;|\&lt;br /&gt;
ring2([zaehler:Produktion],-20,30,undef,undef,&amp;quot;PV kWh&amp;quot;,130,[(-10,0,-0.001,30,10,60,30,90)],&amp;quot;2&amp;quot;,[test:Bezug],-20,30,undef,undef,&amp;quot;Bezug&amp;quot;,[(-10,0,-0.001,30,10,60,30,90)],&amp;quot;2&amp;quot;,undef,undef,&amp;quot;0,1,1,0,1&amp;quot;)\&lt;br /&gt;
&amp;quot;Farbe linear, ringMode 1&amp;quot;|\&lt;br /&gt;
ring2([zeahler:Produktion],-20,30,0,120,&amp;quot;PV kWh&amp;quot;,130,undef,&amp;quot;2&amp;quot;,[test:Bezug],-20,30,0,120,&amp;quot;Bezug&amp;quot;,undef,&amp;quot;2&amp;quot;,undef,undef,&amp;quot;0,1,1,0,1&amp;quot;)\&lt;br /&gt;
&amp;quot;Farbe linear, ringMode 2&amp;quot;|\&lt;br /&gt;
ring2([zaehler:Produktion],0,30,60,120,&amp;quot;PV kWh&amp;quot;,130,undef,&amp;quot;2&amp;quot;,[test:Bezug],-20,0,0,120,&amp;quot;Bezug&amp;quot;,undef,&amp;quot;2&amp;quot;,undef,undef,&amp;quot;0,,,0,2&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:ring2_ringMode.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;icon_ring&#039;&#039;&#039;-Funktionen ====&lt;br /&gt;
===== Farbskalierte Temperaturanzeige mit einem Icon mit Hilfe der SVG-Funktionen &#039;&#039;&#039;icon_temp_ring/icon_temp_mring&#039;&#039;&#039; =====&lt;br /&gt;
Diese Funktionen basieren auf den obigen temp_ring-Funktionen, zusätzlich wird ein SVG-Icon dargestellt. Die Farbe des Icons kann mit @ an den Iconnamen angehängt werden, ansonsten wird die Farbe der Temperatur für das Icon verwendet. Die Größe des Icons kann skaliert werden, ebenso kann die Positionen des Icons verschoben werden.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_temp_ring/icon_temp_mring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_temp_ring/icon_temp_mring ($icon,$temp_value,$temp_min,$temp_max,$size,$lightring,$lightnumber,$decFont) &lt;br /&gt;
&lt;br /&gt;
$icon        # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position,Rotation&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position, Rotation (0-360) sind optional&lt;br /&gt;
$temp_value  # Temperatur&lt;br /&gt;
$temp_min,   # minimale Temperatur, optional, default=-20&lt;br /&gt;
$temp_max,   # maximale Temperatur, optional, default=60&lt;br /&gt;
$size,       # Größe der Grafik, optional, default=80&lt;br /&gt;
$lightring,  # Helligkeit des Ringes (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFont     # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_Heizung_temp DOIF ##&lt;br /&gt;
attr di_Heizung_temp uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
icon_temp_ring(&amp;quot;temp_outside&amp;quot;,[vaillant:Aussentemp],-15,40)|\&lt;br /&gt;
icon_temp_mring(([vaillant:Flame] eq &amp;quot;off&amp;quot;?&amp;quot;sani_boiler_temp\@white&amp;quot;:&amp;quot;sani_boiler_temp\@Darkorange&amp;quot;),[vaillant:Vorlauf],15,70)|\&lt;br /&gt;
icon_temp_mring(([vaillant:Pumpenstatus] eq &amp;quot;4&amp;quot; ? &amp;quot;sani_buffer_temp_down\@Darkorange&amp;quot; : &amp;quot;sani_buffer_temp_down\@white&amp;quot;),[vaillant:WWSpeicher],15,70)|\&lt;br /&gt;
icon_temp_mring(([Zirk] eq &amp;quot;off&amp;quot;?&amp;quot;sani_pump\@white&amp;quot;:&amp;quot;sani_pump\@Darkorange&amp;quot;),[ESPEasy_ESP_Temp_Zirkulation:Temperature],15,70)|\&lt;br /&gt;
icon_temp_mring(([vaillant:Pumpenstatus] eq &amp;quot;on&amp;quot; ? &amp;quot;sani_floor_heating\@Darkorange&amp;quot; : &amp;quot;sani_floor_heating_neutral\@white&amp;quot;),[ESPEasy_ESP_Temp_Vorlauf:Temperature],15,70)|\&lt;br /&gt;
icon_temp_mring(&amp;quot;sani_floor_heating_neutral\@white&amp;quot;,[ESPEasy_ESP_Temp_Keller_Ruecklauf:Temperature],15,70)|&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_temp_ring_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Feuchtigkeitsanzeige mit einem Icon mit Hilfe der SVG-Funktionen &#039;&#039;&#039;icon_hum_ring/icon_hum_mring&#039;&#039;&#039; =====&lt;br /&gt;
Diese Funktionen basieren auf den obigen hum_ring-Funktionen, zusätzlich wird ein SVG-Icon dargestellt. Die Farbe des Icons kann mit @ an den Iconnamen angehängt werden, ansonsten wird die Farbe der Feuchtigkeit für das Icon verwendet. Die Größe des Icons kann skaliert werden, ebenso kann die Positionen des Icons verschoben werden. &lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_hum_ring/icon_hum_mring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_hum_ring/icon_hum_mring ($icon,$hum_value,$size,$lightring,$lightnumber,$decFont) &lt;br /&gt;
&lt;br /&gt;
$icon        # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position,Rotation&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position, Rotation sind optional&lt;br /&gt;
$hum_value   # Feuchtigkeit&lt;br /&gt;
$size        # Größe der Grafik, optional, default=80&lt;br /&gt;
$lightring   # Helligkeit des Ringes (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFont     # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_icon_hum_ring DOIF ##&lt;br /&gt;
attr di_icon_hum_ring room test5&lt;br /&gt;
attr di_icon_hum_ring uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;klein ohne Farbverlauf&amp;quot;|icon_hum_mring(&amp;quot;weather_humidity&amp;quot;,[Aussensensor:humidity],60)\&lt;br /&gt;
&amp;quot;normal groß mit Farbverlauf&amp;quot;|icon_hum_ring(&amp;quot;weather_humidity&amp;quot;,[Aussensensor:humidity])\&lt;br /&gt;
&amp;quot;groß ohne Farbverlauf aufgehellt&amp;quot;|icon_hum_mring(&amp;quot;weather_humidity&amp;quot;,[Aussensensor:humidity],100,80)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_hum_ring_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige eines Icons mit einem Zahlenwert mit Hilfe der universellen SVG-Funktion &#039;&#039;&#039;icon_ring/icon_mring/icon_uring&#039;&#039;&#039; =====&lt;br /&gt;
Diese Funktionen basieren auf der universellen ring-Funktion. Die Farbe des dargestellten Icons und des Wertes kann abhängig vom Wert bestimmt werden. Die Funktion &#039;&#039;&#039;icon_ring&#039;&#039;&#039; stellt den Farbring mit Farbverlauf dar, die Funktion &#039;&#039;&#039;icon_mring&#039;&#039;&#039; stellt den Farbring einfarbig dar. Die universelle Funktion &#039;&#039;&#039;icon_uring&#039;&#039;&#039; kann über den Parameter &#039;&#039;&#039;$model&#039;&#039;&#039; das Erscheinungsbild der Grafik verändern.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_ring/icon_mring/icon_uring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_ring ($icon,$value,$min,$max,$minColor,$maxColor, $unit,$decFont,$size,$colorRef,$lightness,$model)&lt;br /&gt;
&lt;br /&gt;
icon_mring ($icon,$value,$min,$max,$minColor,$maxColor, $unit,$decFont,$size,$colorRef,$lightness)&lt;br /&gt;
&lt;br /&gt;
icon_uring ($model,$icon,$value,$min,$max,$minColor,$maxColor, $unit,$decFont,$size,$colorRef,$lightness)&lt;br /&gt;
&lt;br /&gt;
$icon      # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position,Rotation&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position, Rotation sind optional&lt;br /&gt;
$value     # darzustellender Wert&lt;br /&gt;
$min       # minimaler Wert, optional, default=0&lt;br /&gt;
$max       # maximaler Wert, optional, default=100&lt;br /&gt;
$minColor  # Farbe (hue: 0-360) des kleinsten Wertes, optional, default = undef&lt;br /&gt;
$maxColor  # Farbe (hue: 0-360) des maximalen Wertes, optional, default = undef&lt;br /&gt;
$unit      # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$decFont   # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Style-SVG-Attribute Wert&amp;gt;,&amp;lt;Style-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$size      # Größe der Grafik, optional, default = 100&lt;br /&gt;
$colorRef  # Referenz auf eine Funktion, die zu einem Wert einen Farbwert (hue: 0-360) bestimmt, oder eine Referenz auf eine Arrayliste mit Grenzwerten und Farben, optional, default = undef&lt;br /&gt;
$lightness  # Helligkeit einzelner Elemente (0-100) &amp;quot;&amp;lt;ring&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;minMax&amp;gt;,&amp;lt;unit&amp;gt;,&amp;lt;value&amp;gt;,&amp;lt;icon&amp;gt;&amp;quot;, optional, default: &amp;quot;50,50,50,40,50,40&amp;quot;&lt;br /&gt;
$model      # &#039;&amp;lt;color gradient&amp;gt;,&amp;lt;min/max&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;pointer&amp;gt;,&amp;lt;mode&amp;gt;&#039;,&lt;br /&gt;
            # &amp;lt;color gradient&amp;gt;: 1 für monochrom&lt;br /&gt;
            # &amp;lt;min/max&amp;gt;: Style-SVG-Attribute oder 1 zum Anzeigen der Min-/Maxwerte&lt;br /&gt;
            # &amp;lt;inner ring&amp;gt;: Style-SVG-Attribute oder 1 zum Anzeigen des Innenringes&lt;br /&gt;
            # &amp;lt;pointer&amp;gt;: Breite des Zeigers in Pixel&lt;br /&gt;
            # &amp;lt;mode&amp;gt;: 0 Standard Min. - Max., 1 negativ - Null - positiv, 2 Null - negativ/positiv&lt;br /&gt;
            # alle Parameter sind optional, default keine Angaben: &#039;,,,,,,&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird &#039;&#039;&#039;$colorRef&#039;&#039;&#039; nicht angegeben, so wird der Farbwert zwischen &#039;&#039;&#039;$minColor&#039;&#039;&#039; und &#039;&#039;&#039;$maxColor&#039;&#039;&#039; linear interpoliert&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_icon_ring DOIF ##&lt;br /&gt;
attr di_icon_ring uiTable {package ui_Table}\&lt;br /&gt;
\&lt;br /&gt;
icon_ring (&#039;sani_floor_heating_neutral&#039;,[Heizenergie:Vortag_hc],0,150,120,0,&#039;kWh&#039;)|\&lt;br /&gt;
icon_mring (&#039;fuel&#039;,[Tankstelle:Diesel],1.10,1.30,120,0,&#039;€&#039;,2)|\&lt;br /&gt;
icon_uring (&#039;0,1,1&#039;,&amp;quot;air&amp;quot;,[ESPEasy_Eingang_CO2:PPM],400,1200,undef,undef,&#039;ppm&#039;,0,100,[(600,120,1000,60,1200,0)])|\&lt;br /&gt;
icon_uring (&#039;0,1&#039;,&#039;Zisterne&#039;,([Wasserzisterne]/3.4),0,100,0,120,&#039;%&#039;,0)##/\&lt;br /&gt;
\&lt;br /&gt;
icon_uring (&#039;1,1,0,8&#039;,&amp;quot;measure_water_meter&amp;quot;,[Wasserverbrauch:heute],0,600,120,0,&#039;l&#039;,0)|\&lt;br /&gt;
icon_uring (&#039;0,fill:white,opacity:0.4&#039;,([vaillant:Pumpenstatus] eq &#039;4&#039; ? &#039;sani_buffer_temp_down@Darkorange&#039; : &#039;sani_buffer_temp_down@white&#039;),[vaillant:Umlaufmenge],0,20,120,0,&#039;l/min&#039;)|\&lt;br /&gt;
icon_uring(&#039;0,1,1,4&#039;,&#039;weather_barometric_pressure&#039;,[vaillant:Wasserdruck],0,3,undef,undef,&#039;bar&#039;,1,100,[(0.8,0,1,60,1.5,120,1.7,60,3,0)])|\&lt;br /&gt;
icon_uring(&#039;0,opacity:0.8,1,6&#039;,&#039;sani_water_tap&#039;,[vaillant:HwcHours_hoursum2_value],0,2000,120,0,&#039;h&#039;,0)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_ring_bsp.png|ohne|mini]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Temperatur- und Feuchtigkeitsanzeige mit einem Icon mit Hilfe der SVG-Funktion &#039;&#039;&#039;icon_temp_hum_ring&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe ist jeweils abhängig vom dargestellten Temperatur- bzw. Feuchtigkeitswert. Die Helligkeit der Farbgebung ist einstellbar:&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_temp_hum_ring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_temp_hum_ring ($icon,$temp_value,$hum_value,$temp_min,$temp_max,$size, $lightring,$lightnumber,$decFontTemp,$decFontHum)&lt;br /&gt;
&lt;br /&gt;
$icon      # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position,Rotation&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position, Rotation sind optional&lt;br /&gt;
$temp_value # Temperatur&lt;br /&gt;
$hum_value  # Feuchtigkeit&lt;br /&gt;
$temp_min   # minimale Temperatur, optional, default=-20&lt;br /&gt;
$temp_max   # maximale Temperatur, optional, default=60&lt;br /&gt;
$size       # Größe der Grafik, optional, default=90&lt;br /&gt;
$lightring   # Helligkeit des Ringes (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFontTemp # Temperatur: &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$decFontHum  # Feuchtigkeit: &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_icon_temp_hum_ring DOIF ##&lt;br /&gt;
attr di_icon_temp_hum_ring uiTable {package ui_Table}\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;normal&amp;quot;|icon_temp_hum_ring(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature],[Aussensensor:humidity])\&lt;br /&gt;
&amp;quot;mit Normalschrift&amp;quot;|icon_temp_hum_ring(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature],[Aussensensor:humidity], undef,undef,undef,undef,undef,&amp;quot;1,font-weight:normal&amp;quot;,&amp;quot;0,font-weight:normal&amp;quot;)\&lt;br /&gt;
&amp;quot;größer aufgehellt&amp;quot;|icon_temp_hum_ring(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature],[Aussensensor:humidity], undef,undef,120,undef,80)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_temp_hum_ring.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige von zwei Temperaturwerten mit einem Icon mit Hilfe der SVG-Funktion &#039;&#039;&#039;icon_temp_temp_ring&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe ist jeweils abhängig vom dargestellten Temperaturwert. Die Helligkeit der Farbgebung ist einstellbar:&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_temp_temp_ring&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_temp_temp_ring ($icon,$temp1_value,$temp2_value,$temp_min,$temp_max,$size, $lightring,$lightnumber,$decFontTemp1,$decFontTemp2)&lt;br /&gt;
&lt;br /&gt;
$icon        # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position,Rotation&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position, Rotation sind optional&lt;br /&gt;
$temp1_value # erster Temperaturwert&lt;br /&gt;
$temp2_value # zweiter Temperaturwert&lt;br /&gt;
$temp_min    # minimale Temperatur, optional, default=-20&lt;br /&gt;
$temp_max    # maximale Temperatur, optional, default=60&lt;br /&gt;
$size        # Größe der Grafik, optional, default=90&lt;br /&gt;
$lightring   # Helligkeit des Ringes (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFontTemp1 # Temperatur1: &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$decFontTemp2 # Temperatur2: &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_icon_temp_temp_ring DOIF ##&lt;br /&gt;
attr di_icon_temp_temp_ring uiTable {package ui_Table}\&lt;br /&gt;
## Größe 120%\&lt;br /&gt;
&amp;quot;FB-Heizung&amp;quot;|icon_temp_temp_ring(([vaillant:Pumpenstatus] eq &amp;quot;on&amp;quot; ? &amp;quot;sani_floor_heating\@Darkorange&amp;quot; : &amp;quot;sani_floor_heating_neutral\@white&amp;quot;),[ESPEasy_ESP_Temp_Vorlauf:Temperature],[ESPEasy_ESP_Temp_Keller_Ruecklauf:Temperature],15,70,120)\&lt;br /&gt;
\&lt;br /&gt;
## Größe 120%, Normalschrift\&lt;br /&gt;
&amp;quot;Temperatur&amp;quot;,&amp;quot;Taupunkt&amp;quot;|icon_temp_temp_ring(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature],[Aussensensor:dewpoint],undef,undef,120,undef,undef,&amp;quot;1,font-weight:normal&amp;quot;,&amp;quot;1,font-weight:normal&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_temp_temp_ring.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige von zwei Zahlenwerten mit einem Icon mit Hilfe der universellen SVG-Funktion &#039;&#039;&#039;icon_ring2&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe der dargestellten Werte kann abhängig vom Wert bestimmt werden.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_ring2&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_ring2 ($icon,$value1,$min1,$max1,$minColor1,$maxColor1,$unit1,$size,$colorFunc1,$decFont1, $value2,$min2,$max2,$minColor2,$maxColor2,$unit2,$colorFunc2,$decFont2,$lightnesss,$model)&lt;br /&gt;
&lt;br /&gt;
$icon       # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position,Rotation&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position, Rotation sind optional&lt;br /&gt;
$value1     # darzustellender Wert1&lt;br /&gt;
$min1       # minimaler Wert, optional, default=0&lt;br /&gt;
$max1       # maximaler Wert, optional, default=100&lt;br /&gt;
$minColor1  # Farbe (hue: 0-360) des kleinsten Wertes, optional, default = undef&lt;br /&gt;
$maxColor1  # Farbe (hue: 0-360) des maximalen Wertes, optional, default = undef&lt;br /&gt;
$unit1      # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$size       # Größe der Grafik, optional, default = 100&lt;br /&gt;
$colorFunc1 # Funktion, die zu einem Wert einen Farbwert (hue: 0-360) bestimmt, optional, default = undef&lt;br /&gt;
$decFont1   # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$value2     ## darzustellender Wert2&lt;br /&gt;
...&lt;br /&gt;
$unit2      # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$colorFunc2 # Funktion, die zu einem Wert einen Farbwert (hue: 0-360) bestimmt, optional, default = undef&lt;br /&gt;
$decFont2   # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
$lightness  # Helligkeit einzelner Elemente (0-100) &amp;quot;&amp;lt;ring&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;minMax&amp;gt;,&amp;lt;unit&amp;gt;,&amp;lt;value&amp;gt;,&amp;lt;icon&amp;gt;&amp;quot;, optional, default: &amp;quot;50,50,50,40,50,40&amp;quot;&lt;br /&gt;
$model      # &#039;&amp;lt;color gradient&amp;gt;,&amp;lt;min/max&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;pointer&amp;gt;,&amp;lt;mode&amp;gt;&#039;,&lt;br /&gt;
            # &amp;lt;color gradient&amp;gt;: 1 für monochrom&lt;br /&gt;
            # &amp;lt;min/max&amp;gt;: Style-SVG-Attribute oder 1 zum Anzeigen der Min-/Maxwerte&lt;br /&gt;
            # &amp;lt;inner ring&amp;gt;: Style-SVG-Attribute oder 1 zum Anzeigen des Innenringes&lt;br /&gt;
            # &amp;lt;pointer&amp;gt;: Breite des Zeigers in Pixel&lt;br /&gt;
            # &amp;lt;mode&amp;gt;: 0 Standard Min. - Max., 1 negativ - Null - positiv, 2 Null - negativ/positiv&lt;br /&gt;
            # alle Parameter sind optional, default keine Angaben: &#039;,,,,,,&#039;&lt;br /&gt;
&lt;br /&gt;
Argumente für den zweiten Wert entsprechend den Argumenten des ersten Wertes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird &#039;&#039;&#039;$colorFunc...&#039;&#039;&#039; nicht angegeben, so wird der Farbwert zwischen &#039;&#039;&#039;$minColor...&#039;&#039;&#039; und &#039;&#039;&#039;$maxColor...&#039;&#039;&#039; linear interpoliert.&lt;br /&gt;
&lt;br /&gt;
Bei der Farbangabe des Icons beim Übergabeparameter $icon wird mit &#039;&#039;&#039;\@colorVal2&#039;&#039;&#039; das Icon mit der Farbe des zweiten Wertes eingefärbt. Bei keiner Farbangabe oder &#039;&#039;&#039;\@colorVal1&#039;&#039;&#039; wird das Icon mit der Farbe des ersten Wertes eingefärbt. Ansonsten gilt die allgemeine FHEM-Syntax für Farbgebung von Icons angehängt mit &#039;&#039;&#039;\@&#039;&#039;&#039;.&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_icon_ring2 DOIF ##&lt;br /&gt;
attr di_icon_ring2 uiTable {package ui_Table};;\&lt;br /&gt;
\&lt;br /&gt;
sub himmelsrichtung {\&lt;br /&gt;
my ($richtung)=@_;;\&lt;br /&gt;
my $element=int($richtung/22.5);;\##/&lt;br /&gt;
my @h=(qw&amp;quot;N NNO NO ONO O OSO SO SSO S SSW SW WSW W WNW NW NNW&amp;quot;);;\&lt;br /&gt;
return($h[$element]);;\&lt;br /&gt;
}\&lt;br /&gt;
}\&lt;br /&gt;
&amp;quot;Wallbox&amp;quot;| icon_ring2(&amp;quot;car,1.5,0,-3&amp;quot;,[tesla:Leistung],0,3.6,120,0,&amp;quot;kW&amp;quot;,120,undef,&amp;quot;1,font-weight:normal&amp;quot;,[tesla:Kapazitaet],0,100,0,120,&amp;quot;%&amp;quot;,undef,&amp;quot;0,font-weight:normal&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Wind&amp;quot;|icon_ring2(([Wind:Geschwindigkeit]&amp;gt;0 ? &amp;quot;wind&amp;quot;:&amp;quot;no_wind&amp;quot;).&amp;quot;,1,0,0,&amp;quot;.[Wind:Richtung],[Wind:Geschwindigkeit],0,50,120,0,&amp;quot;km/h&amp;quot;,120,undef,1,[Wind:Richtung],361,361,220,220,([Wind:Geschwindigkeit]&amp;gt;0?himmelsrichtung([Wind:Richtung]):&amp;quot;--&amp;quot;),undef,0)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Strom&amp;quot;|icon_ring2([zaehler:l-Produktion] &amp;gt; 0 ? &amp;quot;sani_solar\@colorVal1&amp;quot;:&amp;quot;fa_bolt\@colorVal2&amp;quot;,[zaehler:l-Produktion],0,3.6,20,120,&amp;quot;PV kW&amp;quot;,150,undef,&amp;quot;1,,font-size:50%;fill:white&amp;quot;,[zaehler:l-Bezug,0],0,2,120,0,&amp;quot;Netz kW&amp;quot;,undef,&amp;quot;1,,font-size:50%;fill:white&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_ring2.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;bar&#039;&#039;&#039;-Funktionen ====&lt;br /&gt;
===== Farbskalierte Anzeige der Temperatur in Balkenform mit Hilfe der SVG-Funktionen &#039;&#039;&#039;temp_bar/temp_mbar&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe der dargestellten Temperatur ist abhängig vom Temperaturwert. Die Helligkeit der Farbgebung ist einstellbar. Bei der &#039;&#039;&#039;temp_mbar&#039;&#039;&#039;-SVG-Funktion wird der Balken einfarbig dargestellt.&lt;br /&gt;
&lt;br /&gt;
Farbskalierung der &#039;&#039;&#039;temp_bar&#039;&#039;&#039;-SVG-Funktion:&lt;br /&gt;
[[Datei:Farbskalierung temp_bar_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
Farbskalierung der &#039;&#039;&#039;temp_mbar&#039;&#039;&#039;-SVG-Funktion:&lt;br /&gt;
[[Datei:Farbskalierung temp_mbar_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;temp_bar/temp_mbar&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
temp_bar/temp_mbar ($temp_value,$temp_min,$temp_max, $header,$width,$height,$size, $light,$lightnumber,$decFont)&lt;br /&gt;
&lt;br /&gt;
$temp_value  # Temperaturwert&lt;br /&gt;
$temp_min    # minimale Temperatur, optional, default=-20&lt;br /&gt;
$temp_max    # maximale Temperatur, optional, default=60&lt;br /&gt;
$header      # Überschrift, optional, default= undef (keine)&lt;br /&gt;
$width       # Breite der Grafik, optional, default=63&lt;br /&gt;
$height      # Höhe der Grafik, optional, default=60&lt;br /&gt;
$size        # Größe der Grafik, optional, default=100&lt;br /&gt;
$light       # Helligkeit der Grafik (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFont     # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional, default = 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_temp_bar DOIF ##&lt;br /&gt;
attr di_temp_bar uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;standard&amp;quot;|temp_bar([Aussensensor:temperature])\&lt;br /&gt;
&amp;quot;heller&amp;quot;|temp_bar([Aussensensor:temperature],undef,undef,undef,undef,undef,undef,80)\&lt;br /&gt;
&amp;quot;monochrom&amp;quot;|temp_mbar([Aussensensor:temperature])\&lt;br /&gt;
&amp;quot;kleiner&amp;quot;|temp_bar([Aussensensor:temperature],undef,undef,undef,undef,undef,80)\&lt;br /&gt;
&amp;quot;mit Überschrift&amp;quot;|temp_bar([Aussensensor:temperature],undef,undef,&amp;quot;Außen&amp;quot;)\&lt;br /&gt;
&amp;quot;hoch&amp;quot;|temp_bar([Aussensensor:temperature],undef,undef,undef,undef,100)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:temp_bar_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige der Feuchtigkeit in Balkenform mit Hilfe der SVG-Funktionen &#039;&#039;&#039;hum_bar/hum_mbar&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe der dargestellten Feuchtigkeit ist abhängig vom Feuchtigkeitswert. Die Helligkeit der Farbgebung ist einstellbar. Bei der &#039;&#039;&#039;hum_mbar&#039;&#039;&#039;-SVG-Funktion wird der Balken einfarbig dargestellt.&lt;br /&gt;
&lt;br /&gt;
Farbskalierung der &#039;&#039;&#039;hum_bar&#039;&#039;&#039;-SVG-Funktion:&lt;br /&gt;
[[Datei:Farbskalierung hum_bar_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
Farbskalierung der &#039;&#039;&#039;hum_mbar&#039;&#039;&#039;-SVG-Funktion:&lt;br /&gt;
[[Datei:Farbskalierung hum_mbar_scaling.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;hum_bar/hum_mbar&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
hum_bar/hum_mbar ($hum_value,$header,$width,$height,$size, $light,$lightnumber,$decFont)&lt;br /&gt;
&lt;br /&gt;
$hum_value   # Feuchtigkeitswert&lt;br /&gt;
$header      # Überschrift, optional, default = undef (keine)&lt;br /&gt;
$width       # Breite der Grafik, optional, default=63&lt;br /&gt;
$height      # Höhe der Grafik, optional, default=80&lt;br /&gt;
$size        # Größe der Grafik, optional, default=100&lt;br /&gt;
$light       # Helligkeit des der Grafik (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFont     # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional, default = 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_hum_bar DOIF ##&lt;br /&gt;
attr di_hum_bar uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;standard&amp;quot;|hum_bar([Aussensensor:humidity])\&lt;br /&gt;
&amp;quot;heller&amp;quot;|hum_bar([Aussensensor:humidity],undef,undef,undef,undef,80)\&lt;br /&gt;
&amp;quot;monochrom&amp;quot;|hum_mbar([Aussensensor:humidity])\&lt;br /&gt;
&amp;quot;kleiner&amp;quot;|hum_bar([Aussensensor:humidity],undef,undef,undef,80)\&lt;br /&gt;
&amp;quot;mit Überschrift&amp;quot;|hum_bar([Aussensensor:humidity],&amp;quot;Außen&amp;quot;)\&lt;br /&gt;
&amp;quot;hoch&amp;quot;|hum_bar([Aussensensor:humidity],undef,undef,100)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:hum_bar_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige eines Zahlenwertes mit Hilfe der universellen SVG-Funktion &#039;&#039;&#039;bar&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe des dargestellten Wertes kann abhängig vom Wert bestimmt werden.&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;bar&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
bar ($value,$min,$max,$header,$minColor,$maxColor,$unit,$width, $height,$size,$colorFunc,$decFont,$gradient,$light,$lightnumber)&lt;br /&gt;
&lt;br /&gt;
$value     # darzustellender Wert&lt;br /&gt;
$min       # minimaler Wert, optional, default=0&lt;br /&gt;
$max       # maximaler Wert, optional, default=100&lt;br /&gt;
$header    # Überschrift, optional, default = undef (keine)&lt;br /&gt;
$minColor  # Farbe (hue: 0-360) des kleinsten Wertes, optional, default = undef&lt;br /&gt;
$maxColor  # Farbe (hue: 0-360) des maximalen Wertes, optional, default = undef&lt;br /&gt;
$unit      # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$width     # Breite der Grafik, optional, default = 63&lt;br /&gt;
$height    # Höhe der Grafik, optional, default = 60&lt;br /&gt;
$size      # Größe der Grafik, optional, default = 100&lt;br /&gt;
$colorFunc # Funktion, die zu einem Wert einen Farbwert (hue: 0-360) bestimmt, optional, default = undef&lt;br /&gt;
$decFont   # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional, default = 1&lt;br /&gt;
$gradient  # Farbverlauf, optional, undef mit Farbverlauf, 1 ohne Farbverlauf, default = undef&lt;br /&gt;
$light     # Helligkeit der Grafik (light:0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (light:0-100), optional, default=50&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird &#039;&#039;&#039;$colorFunc&#039;&#039;&#039; nicht angegeben, so wird der Farbwert zwischen &#039;&#039;&#039;$minColor&#039;&#039;&#039; und &#039;&#039;&#039;$maxColor&#039;&#039;&#039; linear interpoliert&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
{package ui_Table}&lt;br /&gt;
defmod di_bar DOIF ##&lt;br /&gt;
attr di_bar uiTable {package ui_Table}\&lt;br /&gt;
## von 0 bis 20 in Farben von grün (hue:120) bis rot (hue:0)\&lt;br /&gt;
&amp;quot;Umlaufmenge&amp;quot;|bar([heizung:Umlaufmenge],0,20,&amp;quot;Umlauf&amp;quot;,120,0,&amp;quot;l/min&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## von 0 bis 3 in Farben von rot (hue:0) bis türkis (hue:180)\&lt;br /&gt;
&amp;quot;Wasserdruck&amp;quot;|bar([heizung:Wasserdruck],0,3,undef,0,180,&amp;quot;bar&amp;quot;undef,70,undef,undef,&amp;quot;1,font-size:130%;;font-weight:normal&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Temperaturdarstellung, entspricht dem Funktionsaufruf:\&lt;br /&gt;
## temp_bar ([Aussensensor:temperature],-20,60)\&lt;br /&gt;
&amp;quot;Temperatur&amp;quot;|bar([Aussensensor:temperature],-20,60,undef,undef,undef,&amp;quot;°C&amp;quot;,undef,undef,undef,\&amp;amp;temp_hue)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:bar_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;icon_bar&#039;&#039;&#039;-Funktionen ====&lt;br /&gt;
===== Farbskalierte Anzeige der Temperatur in Balkenform mit Hilfe der SVG-Funktion &#039;&#039;&#039;icon_temp_bar/icon_temp_mbar&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe der dargestellten Temperatur ist abhängig vom Temperaturwert. Die Helligkeit der Farbgebung ist einstellbar. Bei der &#039;&#039;&#039;icon_temp_mbar&#039;&#039;&#039;-SVG-Funktion wird der Balken einfarbig dargestellt.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_temp_bar/icon_temp_mbar&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_temp_bar/icon_temp_mbar ($icon,$temp_value,$temp_min,$temp_max, $header,$width,$height,$size,$light,$lightnumber,$decFont)&lt;br /&gt;
&lt;br /&gt;
$icon        # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position sind optional&lt;br /&gt;
$temp_value  # Temperaturwert&lt;br /&gt;
$temp_min    # minimale Temperatur, optional, default=-20&lt;br /&gt;
$temp_max    # maximale Temperatur, optional, default=60&lt;br /&gt;
$header      # Überschrift, optional, default= undef (keine)&lt;br /&gt;
$width       # Breite der Grafik, optional, default=63&lt;br /&gt;
$height      # Höhe der Grafik, optional, default=75&lt;br /&gt;
$size        # Größe der Grafik, optional, default=100&lt;br /&gt;
$light       # Helligkeit der Grafik (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFont     # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional, default = 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_icon_temp_bar DOIF ##&lt;br /&gt;
attr di_icon_temp_bar room test10&lt;br /&gt;
attr di_icon_temp_bar uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;standard&amp;quot;|icon_temp_bar(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature])\&lt;br /&gt;
&amp;quot;heller&amp;quot;|icon_temp_bar(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature],undef,undef,undef,undef,undef,undef,80)\&lt;br /&gt;
&amp;quot;monochrom&amp;quot;|icon_temp_mbar(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature])\&lt;br /&gt;
&amp;quot;kleiner&amp;quot;|icon_temp_bar(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature],undef,undef,undef,undef,undef,80)\&lt;br /&gt;
&amp;quot;mit Überschrift&amp;quot;|icon_temp_bar(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature],undef,undef,&amp;quot;Außen&amp;quot;)\&lt;br /&gt;
&amp;quot;hoch&amp;quot;|icon_temp_bar(&amp;quot;temp_outside&amp;quot;,[Aussensensor:temperature],undef,undef,undef,undef,100)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_temp_bar_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige der Feuchtigkeit in Balkenform mit Hilfe der SVG-Funktionen &#039;&#039;&#039;icon_hum_bar/icon_hum_mbar&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe der dargestellten Feuchtigkeit ist abhängig vom Feuchtigkeitswert. Die Helligkeit der Farbgebung ist einstellbar. Bei der &#039;&#039;&#039;icon_hum_mbar&#039;&#039;&#039;-SVG-Funktion wird der Balken einfarbig dargestellt.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_hum_bar/icon_hum_mbar&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_hum_bar/icon_hum_mbar ($icon,$hum_value,$header,$width,$height,$size, $light,$lightnumber,$decFont)&lt;br /&gt;
&lt;br /&gt;
$icon        # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position sind optional&lt;br /&gt;
$hum_value   # Temperaturwert&lt;br /&gt;
$header      # Überschrift, optional, default = undef (keine)&lt;br /&gt;
$width       # Breite der Grafik, optional, default=63&lt;br /&gt;
$height      # Höhe der Grafik, optional, default=75&lt;br /&gt;
$size        # Größe der Grafik, optional, default=100&lt;br /&gt;
$light       # Helligkeit des der Grafik (0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (0-100), optional, default=50&lt;br /&gt;
$decFont     # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional, default = 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_icon_hum_bar DOIF ##&lt;br /&gt;
attr di_icon_hum_bar uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;standard&amp;quot;|icon_hum_bar(&amp;quot;temperature_humidity&amp;quot;,[Aussensensor:humidity])\&lt;br /&gt;
&amp;quot;heller&amp;quot;|icon_hum_bar(&amp;quot;temperature_humidity&amp;quot;,[Aussensensor:humidity],undef,undef,undef,undef,80)\&lt;br /&gt;
&amp;quot;monochrom&amp;quot;|icon_hum_mbar(&amp;quot;temperature_humidity&amp;quot;,[Aussensensor:humidity])\&lt;br /&gt;
&amp;quot;kleiner&amp;quot;|icon_hum_bar(&amp;quot;temperature_humidity&amp;quot;,[Aussensensor:humidity],undef,undef,undef,80)\&lt;br /&gt;
&amp;quot;mit Überschrift&amp;quot;|icon_hum_bar(&amp;quot;temperature_humidity&amp;quot;,[Aussensensor:humidity],&amp;quot;Außen&amp;quot;)\&lt;br /&gt;
&amp;quot;hoch&amp;quot;|icon_hum_bar(&amp;quot;temperature_humidity&amp;quot;,[Aussensensor:humidity],undef,undef,100)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_hum_bar_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
===== Farbskalierte Anzeige eines Zahlenwertes mit Hilfe der universellen SVG-Funktionen &#039;&#039;&#039;icon_bar/icon_mbar&#039;&#039;&#039; =====&lt;br /&gt;
Die Farbe des dargestellten Wertes und des Icons kann abhängig vom Wert bestimmt werden. Bei der &#039;&#039;&#039;icon_mbar&#039;&#039;&#039;-SVG-Funktion wird der Balken einfarbig dargestellt.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;icon_bar/icon_mbar&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_bar ($icon,$value,$min,$max,$minColor,$maxColor,$unit,$decfont,$header,$width,$height,$size, $colorFunc,$light,$lightnumber)&lt;br /&gt;
&lt;br /&gt;
$icon      # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position,Rotation&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position, Rotation (0-360) sind optional&lt;br /&gt;
$value     # darzustellender Wert&lt;br /&gt;
$min       # minimaler Wert, optional, default=0&lt;br /&gt;
$max       # maximaler Wert, optional, default=100&lt;br /&gt;
$header    # Überschrift, optional, default = undef (keine)&lt;br /&gt;
$minColor  # Farbe (hue: 0-360) des kleinsten Wertes, optional, default = undef&lt;br /&gt;
$maxColor  # Farbe (hue: 0-360) des maximalen Wertes, optional, default = undef&lt;br /&gt;
$unit      # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$decFont   # &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Schrift-SVG-Attribute Wert&amp;gt;,&amp;lt;Schrift-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional, default = 1&lt;br /&gt;
$width     # Breite der Grafik, optional, default = 63&lt;br /&gt;
$height    # Höhe der Grafik, optional, default = 75&lt;br /&gt;
$size      # Größe der Grafik, optional, default = 100&lt;br /&gt;
$colorFunc # Funktion, die zu einem Wert einen Farbwert (hue: 0-360) bestimmt, optional, default = undef&lt;br /&gt;
$light     # Helligkeit der Grafik (light:0-100), optional, default=50&lt;br /&gt;
$lightnumber # Helligkeit der Zahl (light:0-100), optional, default=50&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird &#039;&#039;&#039;$colorFunc&#039;&#039;&#039; nicht angegeben, so wird der Farbwert zwischen &#039;&#039;&#039;$minColor&#039;&#039;&#039; und &#039;&#039;&#039;$maxColor&#039;&#039;&#039; linear interpoliert&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_icon_bar_bsp DOIF ##&lt;br /&gt;
attr di_icon_bar_bsp uiTable {package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
icon_bar (&amp;quot;fuel&amp;quot;,[Tankstelle:Diesel],1.10,1.30,120,0,&amp;quot;€&amp;quot;,2)|\&lt;br /&gt;
icon_bar (&amp;quot;air&amp;quot;,[ESPEasy_Eingang_CO2:PPM],400,1200,120,0,&amp;quot;ppm&amp;quot;,0)|\&lt;br /&gt;
icon_bar (&amp;quot;Zisterne&amp;quot;,([Wasserzisterne]/3.4),0,100,0,120,&amp;quot;%&amp;quot;,0)|\&lt;br /&gt;
icon_bar (([vaillant:Pumpenstatus] eq &amp;quot;off&amp;quot; ? &amp;quot;sani_buffer_temp_down\@Darkorange&amp;quot; : &amp;quot;sani_buffer_temp_down\@white&amp;quot;),[vaillant:Umlaufmenge],0,20,120,0,&amp;quot;l/min&amp;quot;)\&lt;br /&gt;
icon_bar (&amp;quot;measure_water_meter&amp;quot;,[Wasserverbrauch:heute],0,600,120,0,&amp;quot;l&amp;quot;,0)|\&lt;br /&gt;
icon_bar (&amp;quot;weather_barometric_pressure&amp;quot;,[vaillant:Wasserdruck],0,3,0,180,&amp;quot;bar&amp;quot;)|\&lt;br /&gt;
icon_bar (&amp;quot;sani_water_tap&amp;quot;,[vaillant:HwcHours_hoursum2_value],0,2000,120,0,&amp;quot;h&amp;quot;,0)|\&lt;br /&gt;
icon_bar (&amp;quot;sani_floor_heating_neutral&amp;quot;,[Heizenergie:Vortag_hc],0,150,120,0,&amp;quot;kWh&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:icon_bar_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
==== Anzeige eines Werteverlaufs und des aktuellen Wertes mit Hilfe der SVG-Funktion &#039;&#039;&#039;card&#039;&#039;&#039; ====&lt;br /&gt;
Es wird der aktuelle Wert eines Readings, sein zeitlicher Verlauf sowie der maximale und minimale Wert in Form einer Informationskarte visualisiert. Das Erscheinungsbild kann über zahlreiche Parameter individualisiert werden. Die Besonderheit ist das Argument &#039;&#039;&#039;col&amp;lt;Anzahl&amp;gt;&amp;lt;Zeitformat&amp;gt;&#039;&#039;&#039; bei der Angabe des Readings der Form &#039;&#039;&#039;[&amp;lt;Device&amp;gt;:&amp;lt;Reading&amp;gt;:col&amp;lt;Anzahl&amp;gt;&amp;lt;Zeitformat&amp;gt;]&#039;&#039;&#039;. Dadurch werden Daten des Readings temporär im DOIF-Modul gesammelt und für die Erzeugung eines Graphen zur Verfügung gestellt - es sind keine weiteren Definitionen erforderlich. Dabei wird besonders sparsam mit der Datensammlung umgegangen, es werden maximal 72 Werte (in Timeslots)  gespeichert, unabhängig davon wie lange die Zeitspanne ist und wie oft die Daten ankommen. Die Auflösung des Graphen nimmt mit der Zeitspanne ab - es werden immer maximal 72 Werte dargestellt. Daraus ergibt sich bei einer Stunde eine Auflösung von 3600/72 = 50 Sekunden/Eintrag, bei 6 Stunden sind es 6*60/72 = 5 Minuten/Eintrag, für eine Woche 7*24*60/72 = 140 Minuten/Eintrag usw. Die gesammelten Daten werden über den FHEM-Befehl &#039;&#039;&#039;save&#039;&#039;&#039; in versteckten Readings des jeweiligen DOIF-Moduls gespeichert.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;card&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
card ($collect,$header,$icon,$min,$max,$minColor,$maxColor, $unit,$colorRef,$decfont,$prop,$ringModel,$lightness, $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)&lt;br /&gt;
&lt;br /&gt;
$collect   &lt;br /&gt;
# Angabe eines Readings oder eines Arrays mit mehreren Readings der Form [&amp;lt;Device&amp;gt;:&amp;lt;Reading&amp;gt;:col&amp;lt;Anzahl&amp;gt;&amp;lt;Zeitformat&amp;gt;], mit Hilfe des Argumentes col (von collect) wird das Modul angewiesen Daten des Readings über einen bestimmten Zeitraum zu sammeln&lt;br /&gt;
&lt;br /&gt;
col&amp;lt;number&amp;gt;&amp;lt;timeformat&amp;gt; &lt;br /&gt;
# &amp;lt;timeformat&amp;gt;: d Tage, w Wochen, ohne Angabe des Zeitformates wird &amp;lt;Anzahl&amp;gt; in Stunden interpretiert. &lt;br /&gt;
# Beispiele: col (entspricht col24), col1, col12, col1d, col3d, col1w, col4w, col52w usw.&lt;br /&gt;
&lt;br /&gt;
$header    # &amp;quot;&amp;lt;Überschrifttext,&amp;lt;Style-SVG-Text-Attribute&amp;gt;&amp;quot;, optional&lt;br /&gt;
$icon      # &amp;quot;Iconname\@Farbe,Skalierungsfaktor,x-Position,y-Position,Rotation&amp;quot;, \@Farbe, Skalierungsfaktor, x-Position, y-Position, Rotation sind optional&lt;br /&gt;
$min       # minimaler Wert, optional, default=0&lt;br /&gt;
$max       # maximaler Wert, optional, default=100&lt;br /&gt;
$minColor  # Farbe (hue: 0-360) des kleinsten Wertes, optional, default = 0 (rot)&lt;br /&gt;
$maxColor  # Farbe (hue: 0-360) des maximalen Wertes, optional, default = 120 (grün)&lt;br /&gt;
$unit      &lt;br /&gt;
# Einheit des Wertes, optional, default = undef, falls unter $collect ein Array für mehrere Readings angegeben wurde, so werden hier als Array die entsprechenden Einheiten angegeben, zusätzlich kann kommagetrennt pro Einheit Farbe des Graphen angegeben werden&lt;br /&gt;
&lt;br /&gt;
$colorRef  &lt;br /&gt;
# Referenz auf eine Funktion, die zu einem Wert einen Farbwert (hue: 0-360) bestimmt, oder eine Referenz auf eine Arrayliste mit Grenzwerten und Farben, optional, default = undef&lt;br /&gt;
&lt;br /&gt;
$decFont&lt;br /&gt;
# &amp;quot;&amp;lt;Anzahl der Nachkommastellen&amp;gt;,&amp;lt;Style-SVG-Attribute Wert&amp;gt;,&amp;lt;Style-SVG-Attribute Einheit&amp;gt;&amp;quot;, optional&lt;br /&gt;
&lt;br /&gt;
$prop      &lt;br /&gt;
# Eigenschaft von card: &amp;quot;&amp;lt;size&amp;gt;,&amp;lt;y-scaling&amp;gt;,&amp;lt;steps&amp;gt;,&amp;lt;noFooter&amp;gt;,&amp;lt;noColor&amp;gt;,&amp;lt;hring&amp;gt;,&amp;lt;width&amp;gt;&amp;quot;, optional&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;size&amp;gt;: Größe der der Karte, default = 130,&lt;br /&gt;
# &amp;lt;y-scaling&amp;gt;: feste Y-Skalierung: 1, sonst automatische Skalierung,&lt;br /&gt;
# &amp;lt;steps&amp;gt;: 1 für Stufen,&lt;br /&gt;
# &amp;lt;noFooter&amp;gt;: 1 für keine Fußzeile,&lt;br /&gt;
# &amp;lt;noColor&amp;gt;: 1 für graue y-Achsenbeschriftung, &lt;br /&gt;
# &amp;lt;hring&amp;gt;: 1 für Halbringdarstellung, &lt;br /&gt;
# &amp;lt;width&amp;gt;: Breite der Karte, default: 160&lt;br /&gt;
&lt;br /&gt;
$ringModel&lt;br /&gt;
# &#039;&amp;lt;color gradient&amp;gt;,&amp;lt;min/max&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;pointer&amp;gt;,&amp;lt;mode&amp;gt;&#039;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;color gradient&amp;gt;: 1 für monochrom&lt;br /&gt;
# &amp;lt;min/max&amp;gt;: Style-SVG-Attribute oder 1 zum Anzeigen der Min-/Maxwerte&lt;br /&gt;
# &amp;lt;inner ring&amp;gt;: Style-SVG-Attribute oder 1 zum Anzeigen des Innenringes&lt;br /&gt;
# &amp;lt;pointer&amp;gt;: Breite des Zeigers in Pixel&lt;br /&gt;
# &amp;lt;mode&amp;gt;: 0 Standard Min. - Max., 1 negativ - Null - positiv, 2 Null - negativ/positiv&lt;br /&gt;
# alle Parameter sind optional, default keine Angaben: &#039;,,,,,,&#039;&lt;br /&gt;
&lt;br /&gt;
$lightness &lt;br /&gt;
# Helligkeit einzelner Elemente (0-100) &amp;quot;&amp;lt;ring&amp;gt;,&amp;lt;inner ring&amp;gt;,&amp;lt;minMax&amp;gt;,&amp;lt;unit&amp;gt;,&amp;lt;value&amp;gt;,&amp;lt;icon&amp;gt;&amp;quot;, optional, default: &amp;quot;50,50,50,40,50,40&amp;quot;&lt;br /&gt;
&lt;br /&gt;
$collect2  # optionale Angaben für ein zweites Reading (es ist hier nur eine Readingangabe erlaubt)&lt;br /&gt;
$min       # restliche Parameter&lt;br /&gt;
$max       # entsprechen der Syntax&lt;br /&gt;
...        # des ersten Sensors&lt;br /&gt;
$decfonts2 # &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wird &#039;&#039;&#039;$colorRef&#039;&#039;&#039; nicht angegeben, so wird der Farbwert zwischen &#039;&#039;&#039;$minColor&#039;&#039;&#039; und &#039;&#039;&#039;$maxColor&#039;&#039;&#039; linear interpoliert&lt;br /&gt;
Werden mehrere Readings angegeben, so müssen sie alle die gleiche Zeitspanne besitzen (Zeitangabe bei col)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* Anwendungsbeispiel [[DOIF/uiTable_Schnelleinstieg#Visualisierung:_Wetterstation|Wetterstation]]&lt;br /&gt;
* Anwendungsbeispiel [[DOIF/uiTable_Schnelleinstieg#Visualisierung:_aktueller_Spritpreis|Spritpreise]]&lt;br /&gt;
* Anwendungsbeispiel [[DOIF/uiTable_Schnelleinstieg#Visualisierung_und_Steuerung:_Heiztherme|Heiztherme]]&lt;br /&gt;
* svg-Funktion [[DOIF/uiTable_Schnelleinstieg#Farbskalierte_Anzeige_eines_Icons_mit_einem_Zahlenwert_mit_Hilfe_der_universellen_SVG-Funktion_icon_ring.2Ficon_mring.2Ficon_uring|icon_ring]] &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_collect DOIF ##&lt;br /&gt;
attr di_collect uiTable {package ui_Table;;}\&lt;br /&gt;
card([Aussensensor:temperature:col12],&amp;quot;Außen&amp;quot;,&amp;quot;temp_outside&amp;quot;,-10,45,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,undef)|\&lt;br /&gt;
card([Tankstelle:Diesel:col12],&amp;quot;Sprit,fill:darkorange&amp;quot;,&amp;quot;fuel&amp;quot;,&amp;quot;1.00&amp;quot;,&amp;quot;1.40&amp;quot;,120,0,&amp;quot;Diesel €&amp;quot;,undef,&amp;quot;2&amp;quot;,&amp;quot;,,1&amp;quot;)\&lt;br /&gt;
card([zaehler:l-Produktion:col12],undef,[zaehler:l-Produktion] &amp;gt; 0 ? &amp;quot;sani_solar\@colorVal1&amp;quot;:&amp;quot;fa_bolt\@colorVal2&amp;quot;,0,3.6,30,60,&amp;quot;PV kW&amp;quot;,undef,&amp;quot;1,,font-size:50%&amp;quot;)|\&lt;br /&gt;
card([ESPEasy_Eingang_CO2:PPM:col12],undef,&amp;quot;air&amp;quot;,400,1200,120,0,&amp;quot;ppm&amp;quot;,[600,120,1000,60,1200,0],0,undef,&#039;0,1,1&#039;,&amp;quot;50,35,45,35,50,35&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:svgcard.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
defmod di_cards DOIF {}&lt;br /&gt;
attr di_cards uiTable {package ui_Table;;}\&lt;br /&gt;
&amp;quot;Standard&amp;quot;|\&lt;br /&gt;
card([Aussensensor:temperature:col],undef,&amp;quot;temp_outside&amp;quot;,-10,50,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130&amp;quot;)\&lt;br /&gt;
&amp;quot;mit Halbring&amp;quot;|\&lt;br /&gt;
card([Aussensensor:temperature:col],&amp;quot;Außen&amp;quot;,&amp;quot;temp_outside&amp;quot;,-10,50,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,1&amp;quot;)\&lt;br /&gt;
&amp;quot;mit Halbring&amp;quot;,&amp;quot;ohne Fußzeile&amp;quot;,&amp;quot;Breite 110&amp;quot;|\&lt;br /&gt;
card([Aussensensor:temperature:col],&amp;quot;Außen&amp;quot;,&amp;quot;temp_outside&amp;quot;,-10,50,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130,,,1,,1,110&amp;quot;)\&lt;br /&gt;
&amp;quot;Standard&amp;quot;,&amp;quot;Breite 200&amp;quot;|\&lt;br /&gt;
card([Aussensensor:temperature:col],&amp;quot;Außen&amp;quot;,&amp;quot;temp_outside&amp;quot;,-10,50,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,,200&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:di_card_variations.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition mit zwei Readings mit unterschiedlichen Einheiten&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_cards DOIF {}&lt;br /&gt;
attr di_cards uiTable {package ui_Table;;}\&lt;br /&gt;
&amp;quot;Standard&amp;quot;|\&lt;br /&gt;
card([Aussensensor:temperature:col],&amp;quot;Außen&amp;quot;,&amp;quot;temp_outside&amp;quot;,-10,60,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130,,,,&amp;quot;,undef,undef,[outsensor:humidity:col],0,100,undef,undef,&amp;quot;%&amp;quot;,\&amp;amp;hum_hue,&amp;quot;0&amp;quot;)\&lt;br /&gt;
&amp;quot;ohne Header&amp;quot;|\&lt;br /&gt;
card([Aussensensor:temperature:col],undef,&amp;quot;temp_outside&amp;quot;,-10,60,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130,,,,&amp;quot;,undef,undef,[outsensor:humidity:col],0,100,undef,undef,&amp;quot;%&amp;quot;,\&amp;amp;hum_hue,&amp;quot;0&amp;quot;)\&lt;br /&gt;
&amp;quot;ohne Header&amp;quot;,&amp;quot;ohne Fußzeile&amp;quot;|card([Aussensensor:temperature:col],undef,&amp;quot;temp_outside&amp;quot;,-10,60,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130,,,1,&amp;quot;,undef,undef,[outsensor:humidity:col],0,100,undef,undef,&amp;quot;%&amp;quot;,\&amp;amp;hum_hue,&amp;quot;0&amp;quot;)\&lt;br /&gt;
&amp;quot;Als Halbring&amp;quot;|\&lt;br /&gt;
card([Aussensensor:temperature:col],&amp;quot;Außen&amp;quot;,&amp;quot;temp_outside&amp;quot;,-10,60,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130,,,,,1&amp;quot;,undef,undef,[outsensor:humidity:col],0,100,undef,undef,&amp;quot;%&amp;quot;,\&amp;amp;hum_hue,&amp;quot;0&amp;quot;)\&lt;br /&gt;
&amp;quot;ohne Fußzeile&amp;quot;|\&lt;br /&gt;
card([Aussensensor:temperature:col],&amp;quot;Außen&amp;quot;,&amp;quot;temp_outside&amp;quot;,-10,60,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue,&amp;quot;1&amp;quot;,&amp;quot;130,,,1,,1&amp;quot;,undef,undef,[outsensor:humidity:col],0,100,undef,undef,&amp;quot;%&amp;quot;,\&amp;amp;hum_hue,&amp;quot;0&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:di_card_collect2.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinitionen mit mehreren Readings mit gleicher Einheit&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Sprit DOIF ##&lt;br /&gt;
attr Sprit uiTable {package ui_Table;;}\&lt;br /&gt;
card([[Tankstelle:SuperE5:col24],[Tankstelle:Diesel:col24]],&amp;quot;Sprit&amp;quot;,&amp;quot;fuel&amp;quot;,&amp;quot;1.20&amp;quot;,&amp;quot;1.60&amp;quot;,120,0,[&amp;quot;E5&amp;quot;,&amp;quot;Diesel&amp;quot;],undef,&amp;quot;2&amp;quot;,&amp;quot;,,1&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:di_Sprit2.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV DOIF {}&lt;br /&gt;
attr PV DOIF_Readings l_Eigenv: [zaehler:l-Produktion]-[zaehler:l-Lieferung],\&lt;br /&gt;
Eigenv:[zaehler:Produktion]-[zaehler:Lieferung],\&lt;br /&gt;
l_Verbrauch: [zaehler:l-Bezug,0]+[$SELF:l_Eigenv,0],\&lt;br /&gt;
Verbrauch:[zaehler:Bezug]+[$SELF:Eigenv],\&lt;br /&gt;
l_Bezug:-[zaehler:l-Bezug]&lt;br /&gt;
attr PV uiTable {\&lt;br /&gt;
 package ui_Table;;\&lt;br /&gt;
 $SHOWNOSTATE=1;;\&lt;br /&gt;
}\&lt;br /&gt;
card([[zaehler:l-Produktion:col],[$SELF:l_Eigenv:col],[$SELF:l_Bezug:col]],&amp;quot;kW&amp;quot;,&amp;quot;fa_bolt\@silver&amp;quot;,-3.6,3.6,0,90,[&amp;quot;Solar&amp;quot;,&amp;quot;Eigen.&amp;quot;,&amp;quot;Bezug&amp;quot;],[(-1,0,0,30,1,60,3.6,90)],&amp;quot;2&amp;quot;,&amp;quot;167,,1,,,1&amp;quot;,&amp;quot;,,1,6&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:di_card_energie.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition mit mehreren Readings mit einfarbigen Graphen&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_heating DOIF {}&lt;br /&gt;
attr di_heating uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
card([[ESPEasy_ESP_Temp_Vorlauf:Temperature:col],[ESPEasy_ESP_Temp_Keller_Ruecklauf:Temperature:col]],&amp;quot;Umwälzpumpe&amp;quot;,([vaillant:Pumpenstatus] eq &amp;quot;on&amp;quot; ? &amp;quot;sani_floor_heating\@Darkorange&amp;quot; : &amp;quot;sani_floor_heating_neutral\@white&amp;quot;),15,70,undef,undef,[&amp;quot;Vor. °C,red&amp;quot;,&amp;quot;Rück. °C,#287afc&amp;quot;],\&amp;amp;temp_hue,undef,&amp;quot;,,1,,1&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:di_card_pump.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
==== 3d-Balkendarstellung mehrerer Zahlenwerten mit Hilfe der universellen SVG-Funktion &#039;&#039;&#039;cylinder&#039;&#039;&#039; ====&lt;br /&gt;
Es können mehrere Zahlenwerte mit Legende farbig in Balkenform visualisiert werden. Negative Werte werden als Balken nach unten dargestellt, positive nach oben, der Nullpunkt wird automatisch berechnet.&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;cylinder&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
cylinder ($header,$min,$max,$unit,$width,$height,$size,$dec,($value1,$color1,$text1),($value2,$color2,$text2),...&lt;br /&gt;
&lt;br /&gt;
$header     # Überschrift&lt;br /&gt;
$min        # minimaler Wert, optional, default = 0&lt;br /&gt;
$max        # maximaler Wert, optional, default = 100&lt;br /&gt;
$unit       # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$width      # Breite der Grafik, optional, default = wird bei Beschriftungen automatisch angepasst&lt;br /&gt;
$height     # Höhe der Grafik, optional, default = wird automatisch berechnet&lt;br /&gt;
$size       # Größe der Grafik, optional, default = 100&lt;br /&gt;
$dec        # Anzahl der Nachkommastellen, optional, default=1&lt;br /&gt;
$value1     # erster Zahlenwert&lt;br /&gt;
$color1     # HSL-Farbe des ersten Balkens: &amp;quot;&amp;lt;hue&amp;gt;.&amp;lt;saturation&amp;gt;.&amp;lt;lightness&amp;gt;&amp;quot; (hue:0-360,saturation:0-100,lightness:0-100), saturation (default:100) und lightness (default:50) sind optional&lt;br /&gt;
$text1      # Beschriftung des Zahlenwertes in der Legende, optional, default = undef&lt;br /&gt;
$value2     # zweiter Zahlenwert, optional&lt;br /&gt;
$color2     # HSL-Farbe des zweiten Balkens: &amp;quot;&amp;lt;hue&amp;gt;.&amp;lt;saturation&amp;gt;.&amp;lt;lightness&amp;gt;&amp;quot; (hue:0-360,saturation:0-100,lightness:0-100), saturation (default:100) und lightness (default:50) sind optional&lt;br /&gt;
$text2      # Beschriftung des Zahlenwertes in der Legende, optional, default = undef&lt;br /&gt;
...&lt;br /&gt;
Es können weitere Zahlenwerte jeweils mit Farbe und Beschriftung optional angegeben werden &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_cylinder DOIF ##&lt;br /&gt;
attr di_cylinder room Test,wiki&lt;br /&gt;
attr di_cylinder uiTable {package ui_Table}\&lt;br /&gt;
&amp;quot;normal&amp;quot;|cylinder(&amp;quot;&amp;quot;,0,100,&amp;quot;%&amp;quot;,80,undef,undef,0,[Wasserzisterne:state],200,undef)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;mit Überschrift&amp;quot;|cylinder(&amp;quot;Zisterne&amp;quot;,0,100,&amp;quot;%&amp;quot;,80,undef,undef,0,[Wasserzisterne:state],200,undef)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;kleiner&amp;quot;|cylinder(&amp;quot;Zisterne&amp;quot;,0,100,&amp;quot;%&amp;quot;,80,undef,80,0,[Wasserzisterne:state],200,undef)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;hoch&amp;quot;|cylinder(&amp;quot;Zisterne&amp;quot;,0,100,&amp;quot;%&amp;quot;,undef,100,undef,0,[Wasserzisterne:state],200,undef)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;mit Beschriftung&amp;quot;|cylinder(&amp;quot;Zisterne&amp;quot;,0,100,&amp;quot;%&amp;quot;,undef,100,undef,0,[Wasserzisterne:state],200,&amp;quot;Wasserstand&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;mit mehreren Informationen&amp;quot;|cylinder(&amp;quot;Energie&amp;quot;,-20,30,&amp;quot;kWh&amp;quot;,undef,undef,undef,1,[zaehler:Bezug],0,&amp;quot;Bezug&amp;quot;,[zaehler:Produktion],60,&amp;quot;Produktion&amp;quot;,[zaehler:Eigenverbrauch],30,&amp;quot;Eigenverbrauch&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;mit hellen Farben&amp;quot;| cylinder(&amp;quot;Tag&amp;quot;,0,100,&amp;quot;kWh&amp;quot;,undef,undef,undef,1,[Heizenergie:Tagesverbrauch_hc]/100000,&amp;quot;30.100.70&amp;quot;,&amp;quot;letzter&amp;quot;,[Heizenergie:heute_hc]/100000,&amp;quot;60.100.70&amp;quot;,&amp;quot;aktuell&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:cylinder_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
==== Balkendarstellung mehrerer Zahlenwerte mit Hilfe der universellen SVG-Funktion &#039;&#039;&#039;cylinder_bars&#039;&#039;&#039; ====&lt;br /&gt;
Es können mehrere Zahlenwerte mit Legende farbig in Balkenform visualisiert werden. Negative Werte werden als Balken nach unten dargestellt, positive nach oben, der Nullpunkt wird automatisch berechnet. Die &#039;&#039;&#039;cylinder_bars&#039;&#039;&#039;-SVG-Funkton besitzt die gleichen Argumente, wie die obige &#039;&#039;&#039;cylinder&#039;&#039;&#039;-SVG-Funktion, mehrerer Balken werden jedoch nicht übereinander, sondern nebeneinander dargestellt.&lt;br /&gt;
{{Randnotiz|RNText=SVG-uiTable-Funktion &#039;&#039;&#039;cylinder_bars&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
cylinder_bars ($header,$min,$max,$unit,$width,$height,$size,$dec,($value1,$color1,$text1),($value2,$color2,$text2),...&lt;br /&gt;
&lt;br /&gt;
$header     # Überschrift&lt;br /&gt;
$min        # minimaler Wert, optional, default = 0&lt;br /&gt;
$max        # maximaler Wert, optional, default = 100&lt;br /&gt;
$unit       # Einheit des Wertes, optional, default = undef&lt;br /&gt;
$width      # Breite der Grafik, optional, default = wird bei Beschriftungen automatisch angepasst&lt;br /&gt;
$height     # Höhe der Grafik, optional, default = wird automatisch berechnet&lt;br /&gt;
$size       # Größe der Grafik, optional, default = 100&lt;br /&gt;
$dec        # Anzahl der Nachkommastellen, optional, default=1&lt;br /&gt;
$value1     # erster Zahlenwert&lt;br /&gt;
$color1     # HSL-Farbe des ersten Balkens: &amp;quot;&amp;lt;hue&amp;gt;.&amp;lt;saturation&amp;gt;.&amp;lt;lightness&amp;gt;&amp;quot; (hue:0-360,saturation:0-100,lightness:0-100), saturation (default:100) und lightness (default:50) sind optional&lt;br /&gt;
$text1      # Beschriftung des Zahlenwertes in der Legende, optional, default = undef&lt;br /&gt;
$value2     # zweiter Zahlenwert, optional&lt;br /&gt;
$color2     # HSL-Farbe des zweiten Balkens: &amp;quot;&amp;lt;hue&amp;gt;.&amp;lt;saturation&amp;gt;.&amp;lt;lightness&amp;gt;&amp;quot; (hue:0-360,saturation:0-100,lightness:0-100), saturation (default:100) und lightness (default:50) sind optional&lt;br /&gt;
$text2      # Beschriftung des Zahlenwertes in der Legende, optional, default = undef&lt;br /&gt;
...&lt;br /&gt;
Es können weitere Zahlenwerte jeweils mit Farbe und Beschriftung optional angegeben werden &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_wasserverbrauch DOIF ##&lt;br /&gt;
attr di_wasserverbrauch uiTable {package ui_Table;;}\&lt;br /&gt;
cylinder_bars(&amp;quot;Monat&amp;quot;,0,15,&amp;quot;m³&amp;quot;,undef,undef,undef,1,[Wasserverbrauch:monatsdurchschnitt],30,&amp;quot;Durchschnitt&amp;quot;,[Wasserverbrauch:monatsverbrauch]/1000,220,&amp;quot;letzter&amp;quot;,[Wasserverbrauch:monat]/1000,180,&amp;quot;aktuell&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
cylinder_bars(&amp;quot;Monat&amp;quot;,0,15,&amp;quot;m³&amp;quot;,undef,undef,undef,1,[Wasserverbrauch:jan],30,&amp;quot;Januar&amp;quot;,[Wasserverbrauch:feb],220,&amp;quot;Februar&amp;quot;,[Wasserverbrauch:mrz],180,&amp;quot;März&amp;quot;,[Wasserverbrauch:apr],30,&amp;quot;April&amp;quot;,[Wasserverbrauch:mai],220,&amp;quot;Mai&amp;quot;,[Wasserverbrauch:jun],180,&amp;quot;Juni&amp;quot;,[Wasserverbrauch:jul],30,&amp;quot;Juli&amp;quot;,[Wasserverbrauch:aug],220,&amp;quot;August&amp;quot;,[Wasserverbrauch:sep],180,&amp;quot;September&amp;quot;,[Wasserverbrauch:okt],30,&amp;quot;Oktober&amp;quot;,[Wasserverbrauch:nov],220,&amp;quot;November&amp;quot;,[Wasserverbrauch:dez],180,&amp;quot;Dezember&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:cylinder_bars_bsp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
=== Farbskalierte Temperaturanzeige mit Hilfe der Funktion &#039;&#039;&#039;temp&#039;&#039;&#039; ===&lt;br /&gt;
Die Farbe der dargestellten Temperatur ist abhängig vom Temperaturwert:&lt;br /&gt;
[[Datei:Farbskalierung temp.png|600px|ohne]]&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;temp&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
temp ($temp,$size,$icon)&lt;br /&gt;
&lt;br /&gt;
$temp # Temperatur&lt;br /&gt;
$size # Schriftgröße in Pixel (pt), optional&lt;br /&gt;
$icon # Icon, welches vorangestellt wird, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_temp DOIF ##&lt;br /&gt;
attr di_uiTable_temp uiTable {\&lt;br /&gt;
  package ui_Table;;           ## Package für uiTable-Funktionen\&lt;br /&gt;
  $TC{0..2}=&amp;quot;align=&#039;center&#039;&amp;quot;;; ## zentrierte Darstellung aller Tabellenspalten\&lt;br /&gt;
}\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Aussen&amp;quot;|&amp;quot;Bad&amp;quot;|&amp;quot;Warmwasser&amp;quot;                             ## mit | werden Tabellenzellen voneinander getrennt \&lt;br /&gt;
temp([Aussensensor:temperature])|                       ## Anzeige des Readings &#039;temperature&#039; des Gerätes &#039;Aussensensor&#039;  \&lt;br /&gt;
temp([TH_Bad_HM:measured-temp],24,&amp;quot;temp_temperature&amp;quot;)|  ## Schriftgröße 24pt, mit Icon namens temp_temperature\&lt;br /&gt;
temp([T_Warmwasserspeicher:temperature:d1],20)          ## Schriftgröße 20pt&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:Temp.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
=== Farbskalierte Feuchtigkeitsanzeige mit Hilfe der Funktion &#039;&#039;&#039;hum&#039;&#039;&#039; ===&lt;br /&gt;
Die Farbe der dargestellten Feuchtigkeit ist abhängig vom Feuchtigkeitswert:&lt;br /&gt;
[[Datei:Farbskalierung hum.png|350px|ohne]]&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;hum&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
hum ($hum,$size,$icon)&lt;br /&gt;
&lt;br /&gt;
$hum  # Feuchtigkeit&lt;br /&gt;
$size # Schriftgröße in Pixel (pt), optional&lt;br /&gt;
$icon # Icon, welches vorangestellt wird, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_hum DOIF ##&lt;br /&gt;
attr di_uiTable_hum uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
$TC{1}=&amp;quot;align=&#039;center&#039;&amp;quot;;; ## zweite Spalte der Tabelle zentriert\&lt;br /&gt;
}\&lt;br /&gt;
## Tabellendefinition \&lt;br /&gt;
\&lt;br /&gt;
## Anzeige des Readings &#039;humidity&#039; des Thermostats &#039;TH_Bad_HM&#039;  \&lt;br /&gt;
&amp;quot;Bad&amp;quot;|hum ([TH_Bad_HM:humidity])\&lt;br /&gt;
\&lt;br /&gt;
## Feuchtigkeit in Größe 10pt mit Temperatur in einer Tabellenzelle\&lt;br /&gt;
&amp;quot;Aussen&amp;quot;|temp ([Aussensensor:temperature]),hum ([Aussensensor:humidity],10)\&lt;br /&gt;
\&lt;br /&gt;
## Feuchtigkeit in Größe 26pt mit Icon namens &#039;temperature_humidity&#039;\&lt;br /&gt;
&amp;quot;Keller&amp;quot;|hum ([TH_Keller_HM:humidity],26,&amp;quot;temperature_humidity&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable Funktion hum.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
=== Textformatierungen mit Hilfe der Funktion &#039;&#039;&#039;style&#039;&#039;&#039; ===&lt;br /&gt;
Texte werden in Farbe, Größe und Schriftart statisch oder dynamisch formatiert.&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;style&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
style ($text,$color,$font_size,$font_weight)&lt;br /&gt;
&lt;br /&gt;
$text        # anzuzeigender Text&lt;br /&gt;
$color       # CSS color, optional&lt;br /&gt;
$font_size   # Schriftgröße in Pixel (pt), optional&lt;br /&gt;
$font_weight # CSS Schriftart, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Mögliche Werte für &#039;&#039;&#039;&#039;&#039;color&#039;&#039;&#039;&#039;&#039; und &#039;&#039;&#039;&#039;&#039;font_weight&#039;&#039;&#039;&#039;&#039; können in einschlägiger Dokumentation zu CSS nachgeschlagen werden&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_style DOIF ##&lt;br /&gt;
attr di_uiTable_style uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
## statische Farbgebung, Größe, Schriftart \&lt;br /&gt;
style(&amp;quot;Montag&amp;quot;,&amp;quot;orange&amp;quot;)\&lt;br /&gt;
style(&amp;quot;Dienstag&amp;quot;,&amp;quot;red&amp;quot;,14)\&lt;br /&gt;
style(&amp;quot;Mittwoch&amp;quot;,&amp;quot;#00FFFF&amp;quot;,20)\&lt;br /&gt;
style(&amp;quot;Donnerstag&amp;quot;,&amp;quot;blue&amp;quot;,23,&amp;quot;bold&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## dynamische Farbgebung abhängig vom Zustand des Gerätes &#039;Alarm&#039;\&lt;br /&gt;
style(&amp;quot;Alarm&amp;quot;,([Alarm:state] eq &amp;quot;on&amp;quot; ? &amp;quot;red&amp;quot;:&amp;quot;green&amp;quot;))\&lt;br /&gt;
\&lt;br /&gt;
## dynamische Farbgebung des Zustands des Gerätes &#039;Alarm&#039;\&lt;br /&gt;
style([Alarm:state],([Alarm:state] eq &amp;quot;on&amp;quot; ? &amp;quot;red&amp;quot;:&amp;quot;green&amp;quot;))\&lt;br /&gt;
\&lt;br /&gt;
## variabler Text abhängig vom Zustand des Gerätes &#039;Alarm&#039;\&lt;br /&gt;
style(([Alarm:state] eq &amp;quot;on&amp;quot; ? &amp;quot;Alarm aktiv&amp;quot;:&amp;quot;Alarm deaktiviert&amp;quot;),&amp;quot;red&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:Style.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
=== Icon-Darstellung mit Hilfe der Funktion &#039;&#039;&#039;ICON&#039;&#039;&#039; ===&lt;br /&gt;
Mit Hilfe der Funktion &#039;&#039;&#039;ICON&#039;&#039;&#039; kann ein FHEM-Icon dargestellt werden&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;ICON&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
ICON ($icon)&lt;br /&gt;
&lt;br /&gt;
$icon        # Icon mit Farbgebung&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ICON&#039;&#039;&#039; benutzt die Funktion [[DevelopmentFHEMWEB-API#FW_makeImage|FW_makeImage]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* [[DOIF/uiTable Schnelleinstieg#hsv-Funktion für Farbskalierungen|hsv-Funktion]]&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_Table_ICON DOIF ##&lt;br /&gt;
attr di_Table_ICON uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
ICON(&amp;quot;temp_frost&amp;quot;) |  ## Icon ohne Einfärbung\&lt;br /&gt;
ICON(&amp;quot;temp_frost\@blue&amp;quot;) | ## Icon in CSS-Farbe blau\&lt;br /&gt;
ICON(&amp;quot;temp_frost\@#8A2BE2&amp;quot;) | ## Icon in CSS-Farbe #8A2BE2\&lt;br /&gt;
ICON(&amp;quot;temp_frost\@&amp;quot;.([Aussensensor:temperature] &amp;gt; 0 ? &amp;quot;orange&amp;quot;:&amp;quot;blue&amp;quot;))| ## Icon in CSS-Farbe orange über Null Grad, sonst in CSS-Farbe blau\&lt;br /&gt;
ICON(&amp;quot;temp_frost\@&amp;quot;.hsv ([Aussensensor:temperature],-20,40,320,0)) ## Icon in Farbskalierung von violett (-20 °C) bis rot (40 °C) mit Hilfe der Funktion hsv&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable_IC.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
=== Icon-Darstellung mit Text mit Hilfe der Funktion &#039;&#039;&#039;icon_label&#039;&#039;&#039; ===&lt;br /&gt;
Mit Hilfe der Funktion &#039;&#039;&#039;icon_label&#039;&#039;&#039; kann ein FHEM-Icon mit einem angehängten Text/Wert dargestellt werden.&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;icon_label&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon_label ($icon,$text,$color,$color_bg,$pos_left,$pos_top)&lt;br /&gt;
$icon        # FHEM-Icon mit Farboption&lt;br /&gt;
$text        # dargestellter Text&lt;br /&gt;
$color       # Farbe des Textes, optional&lt;br /&gt;
$color       # Hintergrundfarbe des Textes, optional&lt;br /&gt;
$pos_left    # horizontale Position des Textes in px, default -5, optional&lt;br /&gt;
$pos_top     # vertikale Position des Textes in px, default -8, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Anwendungsbeispiele&#039;&#039;&#039;&lt;br /&gt;
* [[DOIF/uiTable Schnelleinstieg#Anzahl der Tage bis zur Abfall-Entsorgung|Abfall]]&lt;br /&gt;
* [[DOIF/uiTable Schnelleinstieg#Visualisierung: aktueller Spritpreis|Sprit]]&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_icon_label DOIF ##&lt;br /&gt;
attr di_uiTable_icon_label uiTable { package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
icon_label(&amp;quot;fuel&amp;quot;,[Tankstelle:Diesel])|\&lt;br /&gt;
icon_label(&amp;quot;fuel&amp;quot;,[Tankstelle:Diesel],&amp;quot;red&amp;quot;)|\&lt;br /&gt;
icon_label(&amp;quot;fuel\@blue&amp;quot;,[Tankstelle:Diesel],&amp;quot;blue&amp;quot;,&amp;quot;#999999&amp;quot;)|\&lt;br /&gt;
icon_label(&amp;quot;fuel\@red&amp;quot;,[Tankstelle:Diesel],&amp;quot;red&amp;quot;,&amp;quot;white&amp;quot;,-10)|\&lt;br /&gt;
icon_label(&amp;quot;fuel&amp;quot;,[Tankstelle:Diesel],&amp;quot;white&amp;quot;,&amp;quot;red&amp;quot;,-5,8)\&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable_icon_label.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
=== Visualisierung eines Gerätes mit Hilfe der Funktion &#039;&#039;&#039;icon&#039;&#039;&#039; ===&lt;br /&gt;
Der Zustand eines Gerätes/Readings wird mit Hilfe eines Icons dargestellt.&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;icon&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
icon ($value,$icon_off,$icon_on,$state_off,$state_on)&lt;br /&gt;
&lt;br /&gt;
$value       # Wert &lt;br /&gt;
$icon_off    # Icon für den Wert off, default &amp;quot;off&amp;quot;&lt;br /&gt;
$icon_on     # Icon für den Wert on, default Icon für Wert &#039;off&#039; in Farbe &#039;DarkOrange&#039;, sonst Icon &#039;on&#039;, wenn $icon_off nicht definiert ist&lt;br /&gt;
$state_off   # Wert zugehörig zum Icon off, default &amp;quot;off&amp;quot;&lt;br /&gt;
$state_on    # Wert zugehörig zum Icon on, default &amp;quot;on&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_icon DOIF ##&lt;br /&gt;
attr di_uiTable_icon uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
 ## Standard-Icon off/on für Standardwert off/on \&lt;br /&gt;
&amp;quot;Lampe&amp;quot;|icon([Lampe:state])    ## entspricht icon([Lampe:state],&amp;quot;off&amp;quot;,&amp;quot;on&amp;quot;,&amp;quot;off&amp;quot;,&amp;quot;on&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Icon für Zustand &#039;off&#039; ist &#039;hue_room_hallway&#039;, für Zustand &#039;on&#039; &#039;hue_room_hallway\@DarkOrange&#039;\&lt;br /&gt;
&amp;quot;Flur&amp;quot;|icon([Lampeflur:state],&amp;quot;hue_room_hallway&amp;quot;)    ## entspricht icon([Lampeflur:state],&amp;quot;hue_room_hallway&amp;quot;,&amp;quot;hue_room_hallway\DarkOrange&amp;quot;,&amp;quot;off&amp;quot;,&amp;quot;on&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Icon für Zustand &#039;off&#039; ist &#039;status_away_2&#039;, für Zustand &#039;on&#039; &#039;status_available\@DarkOrange&#039;\&lt;br /&gt;
&amp;quot;Anwesenheit&amp;quot;|icon([Anwesenheit:state],&amp;quot;status_away_2&amp;quot;,&amp;quot;status_available\@DarkOrange&amp;quot;) \&lt;br /&gt;
\&lt;br /&gt;
## Icon für Zustand &#039;closed&#039; ist &amp;quot;status_locked&amp;quot;, für Zustand &#039;open&#039; &#039;status_open\@DarkOrange&#039;\&lt;br /&gt;
&amp;quot;Haus&amp;quot;|icon([Schloss:state],&amp;quot;status_locked&amp;quot;,&amp;quot;status_open\@DarkOrange&amp;quot;,&amp;quot;closed&amp;quot;,&amp;quot;open&amp;quot;) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable icon.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
=== Schaltbares Icon mit Hilfe der Funktion &#039;&#039;&#039;switch&#039;&#039;&#039; ===&lt;br /&gt;
Der Zustand eines Gerätes/Readings wird mit Hilfe eines Icons dargestellt, er kann über die WEB-Oberfläche durch Anklicken geschaltet werden. Damit der Zustand des Gerätes geschaltet werden kann, muss das Gerät den set-Befehl unterstützen.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;switch&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
switch ($value,$icon_off,$icon_on,$state_off,$state_on)&lt;br /&gt;
&lt;br /&gt;
$value       # [&amp;lt;device&amp;gt;:&amp;lt;reading&amp;gt;] &lt;br /&gt;
$icon_off    # Icon für den Wert off, default &amp;quot;off&amp;quot;&lt;br /&gt;
$icon_on     # Icon für den Wert on, default Icon für Wert &#039;off&#039; in Farbe &#039;DarkOrange&#039;, sonst Icon &#039;on&#039;, wenn $icon_off nicht definiert ist&lt;br /&gt;
$state_off   # Wert zugehörig zum Icon off, default &amp;quot;off&amp;quot;&lt;br /&gt;
$state_on    # Wert zugehörig zum Icon on, default &amp;quot;on&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_switch DOIF ##&lt;br /&gt;
attr di_uiTable_switch uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
## schaltbares Icons in der Webansicht \&lt;br /&gt;
switch([Lampe:state]) | \&lt;br /&gt;
switch([Lampeflur:state],&amp;quot;hue_room_hallway&amp;quot;) |\&lt;br /&gt;
switch([Anwesenheit:state],&amp;quot;status_away_2&amp;quot;,&amp;quot;status_available\@DarkOrange&amp;quot;)|\&lt;br /&gt;
switch([Haus:state],&amp;quot;status_locked&amp;quot;,&amp;quot;status_open\@DarkOrange&amp;quot;,&amp;quot;closed&amp;quot;,&amp;quot;open&amp;quot;)\&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable switch.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
=== Rollladen: Visualisierung und Steuerung mit Hilfe der Funktion &#039;&#039;&#039;shutter&#039;&#039;&#039; ===&lt;br /&gt;
Die aktuelle Position des Rollladens (0 % - 100 %) wird über Icons visualisiert. Das Anklicken eines Symbols steuert den Rollladen auf die entsprechende Position. Prozentwerte zwischen zwei Icon-Werten werden dem nächsthöheren Icon-Wert zugeordnet.&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;shutter&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
shutter ($value,$color,$type)&lt;br /&gt;
&lt;br /&gt;
$value       # [&amp;lt;device&amp;gt;:&amp;lt;reading&amp;gt;] &lt;br /&gt;
$color       # Farbe der aktuellen Rollladenposition, vorangestelltes @ verändert die Farbe des Icons, ohne @ wird der Hintergrund des Icons eingefärbt, default ist @DarkOrange&lt;br /&gt;
$type        # optional, Anzahl der Symbole 2 bis 6, 3 ist default&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [[DOIF/uiTable Schnelleinstieg#Visualisierung und Steuerung von Rollläden|Anwendungsbeispiel]]&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod ui_Table_shutter DOIF ##&lt;br /&gt;
attr ui_Table_shutter uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
shutter([R_Keller:pct],&amp;quot;\@yellow&amp;quot;,2)     ## zwei Symbole für 0 % und 100 %\&lt;br /&gt;
shutter([R_Wohnzimmer_S:pct])            ## entspricht shutter ([R_Wohnzimmer_S:pct],&amp;quot;\@DarkOrange&amp;quot;,3) \&lt;br /&gt;
shutter([R_Wohnzimmer_W1:pct],&amp;quot;blue&amp;quot;,4)  ## vier Symbole \&lt;br /&gt;
shutter([R_Wohnzimmer_W2:pct],&amp;quot;\@red&amp;quot;,5) ## fünf Symbole\&lt;br /&gt;
shutter([R_Wohnzimmer_W3:pct],&amp;quot;red&amp;quot;,6    ## sechs Symbole)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable shutter.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
===  Helligkeit: Visualisierung und Steuerung mit Hilfe der Funktion &#039;&#039;&#039;dimmer&#039;&#039;&#039; ===&lt;br /&gt;
Die aktuelle Helligkeit (0 % - 100 %) wird über Icons visualisiert. Das Anklicken eines Icons bestimmt die Helligkeit der Leuchte. Prozentwerte zwischen zwei Icon-Werten werden dem nächsthöheren Icon-Wert zugeordnet.&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;dimmer&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
dimmer ($value,$color,$type)&lt;br /&gt;
&lt;br /&gt;
$value       # [&amp;lt;device&amp;gt;:&amp;lt;reading&amp;gt;] &lt;br /&gt;
$color       # Farbe der aktuellen Helligkeit, vorangestelltes @ verändert die Farbe des Icons, ohne @ wird der Hintergrund des Icons eingefärbt, default ist @DarkOrange&lt;br /&gt;
$type        # Anzahl der Symbole 2 bis 7, 3 ist default&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_dimmer DOIF ##&lt;br /&gt;
attr di_uiTable_dimmer uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
dimmer([Strauch3:pct],&amp;quot;\@yellow&amp;quot;,2)\&lt;br /&gt;
dimmer([Strauch3:pct]) ## entspricht dimmer([Strauch3:pct],&amp;quot;\@DarkOrange&amp;quot;,3) \&lt;br /&gt;
dimmer([Strauch3:pct],&amp;quot;blue&amp;quot;,4)\&lt;br /&gt;
dimmer([Strauch3:pct],&amp;quot;\@red&amp;quot;,5)\&lt;br /&gt;
dimmer([Strauch3:pct],&amp;quot;red&amp;quot;,6)\&lt;br /&gt;
dimmer([Strauch3:pct],&amp;quot;DarkOrange&amp;quot;,7)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable dimmer.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
===  Vorgabetemperatur eines Thermostats mit Hilfe der Funktion &#039;&#039;&#039;temp_knob&#039;&#039;&#039; ===&lt;br /&gt;
Die aktuelle Vorgabetemperatur eines Thermostats wird über ein Icons visualisiert. Durch Anklicken des Ringes wird die Vorgabetemperatur verändert.&lt;br /&gt;
{{Randnotiz|RNText=uiTable-Funktion &#039;&#039;&#039;temp_knob&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
temp_knob ($value,$color,$set)&lt;br /&gt;
&lt;br /&gt;
$value       # [&amp;lt;device&amp;gt;:&amp;lt;reading&amp;gt;] &lt;br /&gt;
$color       # Farbe der voreingestellten Temperatur, default &amp;quot;Darkorange&amp;quot;&lt;br /&gt;
$set         # set-Befehl, default &amp;quot;set&amp;quot;, sonst muss &amp;quot;set &amp;lt;Readingname&amp;gt;&amp;quot; angegeben werden, falls sich das Reading vom set-Befehl vom angezeigten Reading unterscheidet, wie beim THRESHOLD-Modul&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod ui_Table_temp_knob DOIF ##&lt;br /&gt;
attr ui_Table_temp_knob uiTable {\&lt;br /&gt;
package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
## HM-EU-Thermostat, angezeigt wird das Reading &amp;quot;desired-temp&amp;quot;, geschaltet wird über &amp;quot;set desired-temp&amp;quot; \&lt;br /&gt;
&amp;quot;Dachgeschoss&amp;quot;|temp_knob([TH_DG_HM:desired-temp]) ## entspricht temp_knob([TH_DG_HM:desired-temp],&amp;quot;Darkorange&amp;quot;,&amp;quot;set&amp;quot;) \&lt;br /&gt;
\&lt;br /&gt;
## HM-EU-Thermostat Temperaturanzeige in gelb \ &lt;br /&gt;
&amp;quot;Wohnzimmer&amp;quot;|temp_knob([TH_WZ_HM:desired-temp],&amp;quot;yellow&amp;quot;) \&lt;br /&gt;
\&lt;br /&gt;
## Beim THRESHOLD-Modul wird das Reading &amp;quot;desired_value&amp;quot; angezeigt, geändert wird die Temperatur per &amp;quot;set desired&amp;quot; \&lt;br /&gt;
&amp;quot;Küche&amp;quot;|temp_knob([TH_Kueche:desired_value],&amp;quot;red&amp;quot;,&amp;quot;set desired&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable temp knob.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
==  uiTable-&#039;&#039;&#039;Templates&#039;&#039;&#039; ==&lt;br /&gt;
Die Definition einer oder mehrere Zellen kann zu einem Template zusammengefasst werden. Durch die Nutzung von Templates kann die Definition einer Tabelle erheblich vereinfacht werden. Insb. bei gleichartigen Zellen/Zeilen für verschiedene Geräte/Readings braucht eine aufwendige Definition nicht immer wieder wiederholt werden, sondern kann jeweils mit dem Aufruf eines zuvor definierten Templates realisiert werden.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;Templates&#039;&#039;&#039;&lt;br /&gt;
* Die Definition von Templates muss vor der Tabellendefinition vorgenommen werden&lt;br /&gt;
* Eine Template-Definition beginnt mit dem Schlüsselwort &#039;&#039;&#039;DEF&#039;&#039;&#039;&lt;br /&gt;
* Der Template-Name muss mit &#039;&#039;&#039;TPL_&#039;&#039;&#039; beginnen&lt;br /&gt;
* &#039;&#039;&#039;Template-Definition&#039;&#039;&#039;-Syntax&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
DEF TPL_&amp;lt;Template-Name&amp;gt;(&amp;lt;Zellendefinition mit Platzhaltern: $1,$2,...&amp;gt;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* Templates-Definitionen können in externe Dateien ausgelagert werden&lt;br /&gt;
* Templates-Definitionen können per IMPORT-Befehl aus externen Dateien importiert werden&lt;br /&gt;
* &#039;&#039;&#039;Template-Import&#039;&#039;&#039;-Syntax&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
IMPORT &amp;lt;Pfad mit Dateinamen&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* Innerhalb einer Tabellendefinition können zuvor definierte oder importierte Templates mehrfach genutzt werden&lt;br /&gt;
* &#039;&#039;&#039;Template-Aufruf&#039;&#039;&#039;-Syntax&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
TPL_&amp;lt;Template-Name&amp;gt;(&amp;lt;Übergabeparameter für $1&amp;gt;,&amp;lt;Übergabeparameter für $2&amp;gt;,...)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod ui_Table_Template DOIF ##&lt;br /&gt;
attr ui_Table_Template uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
  $TC{1..3}=&amp;quot;align=&#039;center&#039;&amp;quot;;; ## Spalten 1 bis 3 werden zentriert\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
## Template-Definitionen beginnen vor der Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
## Das Template TPL_raum stellt eine Tabellenzeile dar, die mit Hilfe von uiTable-Funktionen mehrere Tabellenzellen definiert\&lt;br /&gt;
DEF TPL_raum (&amp;quot;$1&amp;quot; | temp([TH_$2_HM:measured-temp]),hum([TH_$2_HM:humidity]) | switch([H_$2:state],&amp;quot;fa_off&amp;quot;) | temp_knob([TH_$2_HM:desired-temp]))\&lt;br /&gt;
\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
## pro Tabellenzeile wird ein Raum mit Hilfe des oben definierten Templates &amp;quot;TPL_raum&amp;quot; dargestellt\&lt;br /&gt;
&amp;quot;Raum&amp;quot;|&amp;quot;Temp./Feuchte&amp;quot;|&amp;quot;Ventil&amp;quot;|&amp;quot;Vorgabetemp.&amp;quot;\&lt;br /&gt;
TPL_raum (Dachgeschoss,DG)  ## der Übergabeparameter &amp;quot;Dachgeschoss&amp;quot; wird im Template &amp;quot;TPL_raum&amp;quot; anstelle von $1 eingesetzt, &amp;quot;DG&amp;quot; wird anstelle von $2 eingesetzt\&lt;br /&gt;
TPL_raum (Bad,Bad)\&lt;br /&gt;
TPL_raum (Kinderzimmer ost,Kz_o)\&lt;br /&gt;
TPL_raum (Kinderzimmer west,Kz_w)\&lt;br /&gt;
TPL_raum (Wohnzimmer,WZ)\&lt;br /&gt;
TPL_raum (Keller,Keller)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable Templates.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
==  Eigene uiTable-Funktionen programmieren ==&lt;br /&gt;
Für die eigenen Bedürfnisse können eigene uiTable-Funktionen programmiert werden. In der Datei [https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DOIF/uiTable.tpl contrib/DOIF/uiTable.tpl] befinden sich alle intern definierten uiTable-Funktion aus dem package ui_Table als Kopie. Diese Funktionen können als Inspiration für eigene Entwicklung dienen. &lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;uiTable-Funktionen&#039;&#039;&#039;&lt;br /&gt;
* Es gibt drei Arten von uiTable-Funktionen, sie werden intern anhand der Rückgabewerte unterschieden&lt;br /&gt;
* uiTable-Funktionen vom Typ 1: &#039;&#039;&#039;HTML&#039;&#039;&#039;, ein Rückgabewert&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
return(&amp;lt;HTML-code&amp;gt;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* uiTable-Funktionen vom Typ 2: &#039;&#039;&#039;Style&#039;&#039;&#039; (entspricht der &#039;&#039;&#039;STY&#039;&#039;&#039;-Funktion), zwei Rückgabewerte&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
return(&amp;lt;value&amp;gt;,&amp;lt;CSS-style&amp;gt;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* uiTable-Funktionen vom Typ 3: &#039;&#039;&#039;Widget&#039;&#039;&#039; (entspricht der &#039;&#039;&#039;WID&#039;&#039;&#039;-Funktion), vier Rückgabewerte&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
return (&amp;lt;value&amp;gt;,&amp;lt;&amp;gt;,&amp;lt;FHEM-widget&amp;gt;,&amp;lt;set-command: &amp;quot;&amp;quot; or &amp;quot;set&amp;quot; or &amp;quot;set &amp;lt;Readingname&amp;gt;&amp;quot;&amp;gt;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* uiTable-Funktionen sind reine Perlfunktionen&lt;br /&gt;
* uiTable-Funktionen sollten im eigenen Package definiert werden, sonst könnten bestehende Perlfunktionen im System überschrieben werden&lt;br /&gt;
* uiTable-Funktionen können in Template-Dateien ausgelagert werden und über IMPORT-Befehl importiert werden, siehe Templates&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_function DOIF ##&lt;br /&gt;
attr di_uiTable_function uiTable {\&lt;br /&gt;
package my_uiTable;; ## eigenes Package mit selbstdefinierten Funktionen\&lt;br /&gt;
\&lt;br /&gt;
## uiTable-Funktion vom Typ &amp;quot;HTML&amp;quot;, Rückgabewert: (HTML-code)\&lt;br /&gt;
\&lt;br /&gt;
sub clock { ## Anzeige aktueller Uhrzeit mit Datum\&lt;br /&gt;
            ## Voraussetzung: contrib/DOIF/doifclock.js muss ins www/pgm2-Verzeichnis kopiert werden\&lt;br /&gt;
            ## Attribut setzen in der Webinstanz: attr &amp;lt;WEB-Instanz&amp;gt; JavaScripts pgm2/doifclock.js \&lt;br /&gt;
  my ($color,$size)=@_;;\&lt;br /&gt;
  $color=&amp;quot;darkorange&amp;quot; if (!defined ($color));; ## $color ist optional, default Darkorange\&lt;br /&gt;
  $size=&amp;quot;20&amp;quot; if (!defined ($size));;           ## $size ist optional, default 20pt\&lt;br /&gt;
  return(&amp;quot;&amp;lt;div class=&#039;doifclock&#039;style=&#039;font-weight:bold;;font-size:&amp;quot;.$size.&amp;quot;pt;;color:&amp;quot;.$color.&amp;quot;;;&#039;&amp;gt;error&amp;lt;/div&amp;gt;&amp;quot;)\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
## uiTable-Funktion vom Typ Style, Rückgabewerte (Wert,CSS-style)\&lt;br /&gt;
\&lt;br /&gt;
sub red_green { ## Farbige Skalierung von Zahlen mit Hilfe der DOIF_hsv-Funktion: von 0 - rot bis 10 - grün\&lt;br /&gt;
    my ($value)=@_;;\&lt;br /&gt;
    return ($value.&amp;quot; KW&amp;quot;,                                                   ## Wert/Text\&lt;br /&gt;
           &amp;quot;font-weight:bold;;color:&amp;quot;.::DOIF_hsv ($value,0,10,0,120,70,100) ## CSS-Style\&lt;br /&gt;
           );;\&lt;br /&gt;
} \&lt;br /&gt;
\&lt;br /&gt;
## uiTable-Funktion vom Typ Widget, Rückgabewerte (Wert,Leer,FHEM-Widget,set-Befehl)\&lt;br /&gt;
\&lt;br /&gt;
sub slider { ## FHEM-Widget Slider, weitere FHEM-Widgets siehe: https://wiki.fhem.de/wiki/FHEMWEB/Widgets\&lt;br /&gt;
    my ($value,$set)=@_;;\&lt;br /&gt;
    $set=&amp;quot;&amp;quot; if (!defined $set);;\&lt;br /&gt;
    return ($value,                   ## Zahlenwert\&lt;br /&gt;
            &amp;quot;&amp;quot;,                       ## leer\&lt;br /&gt;
            &amp;quot;slider,0,0.5,100,1&amp;quot;,     ## FHEM-Widget\&lt;br /&gt;
            $set                      ## set-Befehl des FHEM-Widgets\&lt;br /&gt;
            ) \&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;Uhrzeit/Datum&amp;quot;\&lt;br /&gt;
clock(&amp;quot;yellow&amp;quot;,30)          ## obige Funktion clock\&lt;br /&gt;
&amp;quot;Dimmer&amp;quot;\&lt;br /&gt;
slider([Wohnzimmer:pct])    ## obige Funktion slider\&lt;br /&gt;
&amp;quot;Leistung&amp;quot;\&lt;br /&gt;
red_green([Leistung:state]) ## obige Funktion red_green&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable-functions.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
== Package-Konzept, Auslagerung eigener Funktionen, der &#039;&#039;&#039;IMPORT&#039;&#039;&#039;-Befehl==&lt;br /&gt;
uiTable arbeitet mit Packages. In einem Package sind definierte Funktionen gekapselt, sie kollidieren nicht mit bereits definierten Funktionen in FHEM.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;Package&#039;&#039;&#039;&lt;br /&gt;
* das für die Definition der Tabelle gültige Package wird im Perlblock des uiTable-Attributes angegeben&lt;br /&gt;
* interne uiTable-Funktionen befinden sich im Package &#039;&#039;&#039;ui_Table&#039;&#039;&#039;&lt;br /&gt;
* ohne eine Angabe eines Package befindet man sich im Package &#039;&#039;&#039;main&#039;&#039;&#039;&lt;br /&gt;
* Funktionen außerhalb des gültigen Package müssen mit &amp;lt;package-Name&amp;gt;::&amp;lt;Funktion&amp;gt; angegeben werden&lt;br /&gt;
* externe uiTable-Funktionen können per IMPORT-Befehl importiert werden&lt;br /&gt;
}} &lt;br /&gt;
=== Tabellendefinition im Package main ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod beispiel1 DOIF ##&lt;br /&gt;
attr beispiel1 uiTable ## keine Package-Definition im Perlblock\&lt;br /&gt;
\&lt;br /&gt;
## Tabellendefinition befindet sich im Package main\&lt;br /&gt;
\&lt;br /&gt;
## Funktionen aus dem main-Package können unmittelbar angegeben werden\&lt;br /&gt;
FW_makeImage(&amp;quot;scene_day&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Funktionen aus dem ui_Table-Package müssen mit vorangestelltem Package angegeben werden\&lt;br /&gt;
ui_Table::temp ([Aussensensor:tempaerature])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Tabellendefinition im Package ui_Table ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod beispiel2 DOIF ##&lt;br /&gt;
attr beispiel2 uiTable {\&lt;br /&gt;
  package ui_Table; ## Package-Angabe im Perlblock\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
## Tabellendefinition befindet sich im Package ui_Table\&lt;br /&gt;
\&lt;br /&gt;
## Funktionen aus dem main-Package müssen mit vorangestelltem package angegeben werden, der Name main kann weggelassen werden\&lt;br /&gt;
::FW_makeImage(&amp;quot;scene_day&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## Funktionen aus dem ui_Table-Package können direkt angegeben werden\&lt;br /&gt;
temp ([Aussensensor:temperature])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Eigene uiTable-Funktionen im eigenen Package ===&lt;br /&gt;
Diese Art der Definition bietet sich dann an, wenn man eine eigene uiTable-Funktion nur in einem DOIF nutzen möchte.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod beispiel3 DOIF ##&lt;br /&gt;
attr beispiel3 uiTable {\&lt;br /&gt;
  package $SELF;;  ## Package-Name ist der Name des DOIF-Moduls, dadurch ist der Package-Name eindeutig\&lt;br /&gt;
  sub scene_day {  ## eigene Funktion befindet sich im eigenen Package beispiel3\&lt;br /&gt;
    return (::FW_makeImage(&amp;quot;scene_day&amp;quot;));;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
## Tabellendefinition befindet sich im Package beispiel3\&lt;br /&gt;
\&lt;br /&gt;
## Funktionen aus dem main-Package müssen mit vorangestelltem Package angegeben werden (der Name main kann weggelassen werden)\&lt;br /&gt;
::FW_makeImage(&amp;quot;scene_day&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## interne Funktionen aus dem ui_Table-Package müssen mit vorangestelltem Package ui_Table angegeben werden\&lt;br /&gt;
ui_Table::temp ([Aussensensor:temperature])\&lt;br /&gt;
\&lt;br /&gt;
## eigene Funktionen können direkt angegeben werden\&lt;br /&gt;
scene_day()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Eigene ausgelagerte uiTable-Funktionen ===&lt;br /&gt;
Möchte man das ui_Table-Package um eigene Funktionen erweitern, die man in verschiedenen DOIFs nutzen möchte, so sollte man diese in eine eigene Datei auslagern, die man mit dem IMPORT-Befehl vor der Definition der Tabelle importieren kann.&lt;br /&gt;
&lt;br /&gt;
Ausgelagerte Funktion in einer eigenen Datei z. B. my_uiTable.tpl:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
{ ## Inhalt der Datei my_uiTable.tpl&lt;br /&gt;
  package ui_Table; ## das aktuelle Package  ist ui_Table&lt;br /&gt;
  sub scene_day {   ## eigene Funktion wird zum Package ui_Table hinzugefügt &lt;br /&gt;
    return (::FW_makeImage(&amp;quot;scene_day&amp;quot;));&lt;br /&gt;
  }&lt;br /&gt;
  ## die Datei kann alle Funktionen beinhalten, die man in diversen DOIFs nutzen möchte&lt;br /&gt;
}&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 beispiel4 DOIF ##&lt;br /&gt;
attr beispiel4 uiTable ##\&lt;br /&gt;
\&lt;br /&gt;
IMPORT ./contrib/DOIF/my_uiTable.tpl ## nach dem Import befindet man sich in Package ui_Table erweitert um eigene Funktionen\&lt;br /&gt;
\&lt;br /&gt;
## Tabellendefinition befindet sich im Package ui_Table\&lt;br /&gt;
\&lt;br /&gt;
## Funktionen aus dem main-Package müssen mit vorangestelltem Package angegeben werden (der Name main kann weggelassen werden)\&lt;br /&gt;
::FW_makeImage(&amp;quot;scene_day&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
## interne uiTable-Funktionen aus dem ui_Table-Package können direkt angegeben werden\&lt;br /&gt;
temp ([Aussensensor:temperature])\&lt;br /&gt;
\&lt;br /&gt;
## eigene Funktionen können direkt angegeben werden, da man sich bereits im Package uiTable befinden\&lt;br /&gt;
scene_day()\&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==  &#039;&#039;&#039;hsv&#039;&#039;&#039;-Funktion für Farbskalierungen==&lt;br /&gt;
Mit Hilfe der hsv-Funktion können Texte, Werte oder Icons abhängig vom Wert eingefärbt werden. Es wird durch Vorgabe von Farbsättigung (saturation) und Helligkeit (lightness), linear ein Farbton für einen bestimmten Wert errechnet. Den Farbwert HUE (0 - 360) für den kleinsten sowie größten Wert kann man mit Hilfe eines Color-Pickers bestimmen. Der Rückgabewert ist ein Farbwert in der CSS-Notation.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;hsv-Funktion für Farbskalierungen&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
hsv ($value,$min_value,$max_value,$min_hue,$max_hue,$saturation,$lightness)&lt;br /&gt;
$value      # Wert, Reading&lt;br /&gt;
$min_value  # der kleinste Wert, dieser entspricht dem Farbwert $min_hue&lt;br /&gt;
$max_value  # der größte Wert, dieser entspricht dem Farbwert $max_hue&lt;br /&gt;
$min_hue    # Farbwert für den kleinsten Wert $min_value&lt;br /&gt;
$max_hue    # Farbwert für den größten Wert $max_value&lt;br /&gt;
$saturation # Farbsättigung, default 100, optional&lt;br /&gt;
$lightness  # Farbhelligkeit, default 100, optional&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Die Funktion befindet sich im ui_Table-Package&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinition&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_hsv DOIF ##&lt;br /&gt;
attr di_uiTable_hsv uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
  ## eigene uiTable-Funktionen vom Typ 1 mit einem Rückgabewert als HTML-Code\&lt;br /&gt;
  \&lt;br /&gt;
  sub bat_icon { ## färbt das Icon &#039;measure_battery_100&#039; abhängig vom Wert mit Hilfe der Funktion hsv \&lt;br /&gt;
    my ($value)=@_;;\&lt;br /&gt;
    return(ICON(&amp;quot;measure_battery_100\@&amp;quot;.hsv($value,0,100,0,120,100,100)))\&lt;br /&gt;
  }\&lt;br /&gt;
   \&lt;br /&gt;
  sub bat_icon2 {## zusätzlich zum Farbwert wird ein entsprechendes Icon bestimmt\&lt;br /&gt;
    my($val)=@_;;\&lt;br /&gt;
	my $icon;;\&lt;br /&gt;
	if ($val==0) {\&lt;br /&gt;
	  $icon=&amp;quot;measure_battery_0&amp;quot;;;\&lt;br /&gt;
	} elsif ($val&amp;lt;=25) {\&lt;br /&gt;
	  $icon=&amp;quot;measure_battery_25&amp;quot;;;\&lt;br /&gt;
	} elsif ($val&amp;lt;=50) {\&lt;br /&gt;
	  $icon=&amp;quot;measure_battery_50&amp;quot;;;\&lt;br /&gt;
	} elsif ($val&amp;lt;=75) {\&lt;br /&gt;
	  $icon=&amp;quot;measure_battery_75&amp;quot;;;\&lt;br /&gt;
	} else {\&lt;br /&gt;
	  $icon=&amp;quot;measure_battery_100&amp;quot;;;\&lt;br /&gt;
	}\&lt;br /&gt;
	\&lt;br /&gt;
	my $output=ICON(&amp;quot;$icon\@&amp;quot;.hsv ($val,0,100,0,120,90,100));;\&lt;br /&gt;
    return($output);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
## eingefärbtes Icon 0 % entspricht rot (HSV-Wert 0), 100 % entspricht grün (HSV-Wert 120) mit Direktangabe\&lt;br /&gt;
1|ICON(&amp;quot;measure_battery_100\@&amp;quot;.hsv([bat:level],0,100,0,120,100,100))\&lt;br /&gt;
\&lt;br /&gt;
## gleiche Funktionalität mit Hilfe der oben definierten Funktion bat_icon \&lt;br /&gt;
2|bat_icon([bat:level])\&lt;br /&gt;
\&lt;br /&gt;
## Icon mit Hilfe der oben definierten Funktion bat_icon2\&lt;br /&gt;
3|bat_icon2([bat:level])\&lt;br /&gt;
\&lt;br /&gt;
## Beispiel für die Farbskaliereung von 0 bis 100 % mit der obigen Funktion bat_icon\&lt;br /&gt;
4|bat_icon(0)|bat_icon(10)|bat_icon(20)|bat_icon(30)|bat_icon(40)|bat_icon(50)|bat_icon(60)|bat_icon(70)|bat_icon(80)|bat_icon(90)|bat_icon(100)\&lt;br /&gt;
\&lt;br /&gt;
## Beispiel für die Farbskaliereung von 0 bis 100 % mit der obigen Funktion bat_icon2\&lt;br /&gt;
5|bat_icon2(0)|bat_icon2(10)|bat_icon2(20)|bat_icon2(30)|bat_icon2(40)|bat_icon2(50)|bat_icon2(60)|bat_icon2(70)|bat_icon2(80)|bat_icon2(90)|bat_icon2(100)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable DOIF hsv.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
== Eine for-Schleife mit Hilfe des &#039;&#039;&#039;FOR&#039;&#039;&#039;-Befehls ==&lt;br /&gt;
Mit Hilfe des &#039;&#039;&#039;FOR&#039;&#039;&#039;-Befehls können über eine Schleife aus einer Liste mit Elementen mehrere Tabellenzellen definiert werden. Die Elementenliste (Array) kann über eine Funktion bestimmt werden. Auf diese Weise kann z. B. eine Tabelle für mehrere Geräte einfach definiert werden.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;FOR-Befehl&#039;&#039;&#039;&lt;br /&gt;
* Der FOR-Befehl entspricht einer foreach-Schleife in Perl&lt;br /&gt;
* Syntax: &#039;&#039;&#039;FOR (&amp;lt;Array&amp;gt;,&amp;lt;Zellendefinitionen&amp;gt;)&#039;&#039;&#039;&amp;lt;br&amp;gt;&#039;&#039;&#039;&amp;lt;Array&amp;gt;&#039;&#039;&#039; eine gültige Angabe eines Arrays oder eine Perlfunktion, die ein Array liefert&amp;lt;br&amp;gt;&#039;&#039;&#039;&amp;lt;Zellendefinitionen&amp;gt;&#039;&#039;&#039; Definition einer oder mehrerer Zellen, die Angabe $_ wird durch das jeweilige Element des Arrays ersetzt&lt;br /&gt;
*&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
**{{Link2CmdRef|Anker=DOIF_aggregation|Lang=de|Label=DOIF Aggregationsfunktionen mit Perlfunktion AggrDoIf}}&lt;br /&gt;
**[[DevelopmentModuleAPI#devspec2array|devspec2array]]&lt;br /&gt;
}}&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;Beispieldefinitionen&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_for DOIF ##&lt;br /&gt;
attr di_for uiTable \&lt;br /&gt;
## Temperaturen aller Geräte, die mit &#039;T&#039; beginnen und ein Reading &#039;temperature&#039; haben, sollen in einer Tabelle visualisiert werden\&lt;br /&gt;
FOR(::AggrDoIf(&#039;@&#039;,&#039;^T_&#039;,&#039;temperature&#039;),&amp;quot;$_&amp;quot;|temp([$_:temperature:d2]))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable-FOR-temperature.png|200px|ohne]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_for DOIF ##&lt;br /&gt;
attr di_for uiTable \&lt;br /&gt;
## Anzeige des Batteriestatus aller Geräte, bei denen das Wort &#039;Fenster&#039; vorkommt, die das Readings &#039;battery&#039; haben\ &lt;br /&gt;
FOR(::AggrDoIf(&#039;@&#039;,&#039;Fenster&#039;,&#039;battery&#039;),&amp;quot;$_&amp;quot;|bat([$_:battery]))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable-FOR-battery.png|200px|ohne]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_for DOIF ##&lt;br /&gt;
attr di_for uiTable \&lt;br /&gt;
## Anzeige des Status aller Geräte im System vom Typ &#039;HMS&#039;\&lt;br /&gt;
FOR(::devspec2array(&amp;quot;TYPE=HMS&amp;quot;),&amp;quot;$_&amp;quot;|[$_])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable-FOR-HMS.png|300px|ohne]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_for DOIF ##&lt;br /&gt;
attr di_for uiTable \&lt;br /&gt;
## Elemente einer kommagetrennten Liste sollen jeweils in einer Tabellenzelle in einer Tabellenzeile angezeigt werden\&lt;br /&gt;
FOR(split(&amp;quot;,&amp;quot;,&amp;quot;Mo,Di,Mi,Do,Fr,Sa,So&amp;quot;),ui_Table::style(&amp;quot;$_&amp;quot;,&amp;quot;Darkorange&amp;quot;)|)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable-FOR-split.png|300px|ohne]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_for DOIF ##&lt;br /&gt;
attr di_for uiTable \&lt;br /&gt;
## Durch Leerzeichen getrennte Zeichenketten sollen jeweils in einer Tabellenzelle in einer Tabellenzeile angezeigt werden\&lt;br /&gt;
FOR(qw/Montag Dienstag Mittwoch Donnerstag Freitag/,&amp;quot;$_&amp;quot;|)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable-FOR-qw.png|300px|ohne]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_for DOIF ##&lt;br /&gt;
attr di_for uiTable \&lt;br /&gt;
## das Templates TPL_raum, soll vier mal aufgerufen werden: TPL_raum(1), TPL_raum(2)...\&lt;br /&gt;
## das Templates TPL_raum muss vorher definiert worden sein\&lt;br /&gt;
FOR(1..4,TPL_raum($_))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable-FOR TPL raum.png|600px|ohne]]&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Anwendungsbeispiele&#039;&#039;&#039; ==&lt;br /&gt;
=== &#039;&#039; Visualisierung und Steuerung von &#039;&#039;&#039;Rollläden&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Im folgenden Beispiel werden Rollläden morgens hochgefahren, ebenso wird die Position aller Rollläden visualisiert. Durch Anklicken eines Icons wird der Rollladen auf die entsprechende Position bewegt. &lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* {{Link2CmdRef|Anker=DOIF_Zeitsteuerung_mit_Zeitintervallen|Lang=de|Label=Zeitsteuerung}}&lt;br /&gt;
* uiTable-Funktion [[DOIF/uiTable Schnelleinstieg#Rollladen: Visualisierung und Steuerung mit Hilfe der Funktion shutter|shutter]]&lt;br /&gt;
* uiTable-Funktion [[DOIF/uiTable Schnelleinstieg#Textformatierungen mit Hilfe der Funktion style|style]]&lt;br /&gt;
* [[DOIF/uiTable Schnelleinstieg#uiTable-Templates|Templates]]&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DI_Rollladen DOIF (([Dunkelheit] eq &amp;quot;off&amp;quot; and [06:25-09:00|8]) or [09:00|7]) \&lt;br /&gt;
  ((set R_W_S,R_W_W[1-3] on)) ## Hochfahren der Rollläden im Erdgeschoss morgens\&lt;br /&gt;
DOELSEIF ([Dunkelheit] eq &amp;quot;on&amp;quot;)&lt;br /&gt;
attr DI_Rollladen cmdState oben|unten&lt;br /&gt;
attr DI_Rollladen devStateIcon unten:status_night oben:scene_day&lt;br /&gt;
attr DI_Rollladen icon fts_shutter_automatic&lt;br /&gt;
attr DI_Rollladen uiTable {\&lt;br /&gt;
   package ui_Table;;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
## Template für ein Fenster\&lt;br /&gt;
DEF TPL_shutter(&amp;quot;$1&amp;quot;|shutter([$1:pct]))\&lt;br /&gt;
\&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
style(&amp;quot;Dachgeschoss&amp;quot;,&amp;quot;Darkorange&amp;quot;)|&amp;quot;&amp;quot;\&lt;br /&gt;
TPL_shutter(R_Dachboden)\&lt;br /&gt;
style(&amp;quot;erstes Geschoss&amp;quot;,&amp;quot;Darkorange&amp;quot;)|&amp;quot;&amp;quot;\&lt;br /&gt;
TPL_shutter(R_Bad)\&lt;br /&gt;
TPL_shutter(R_Kinderzimmer1_O)\&lt;br /&gt;
TPL_shutter(R_Kinderzimmer1_S)\&lt;br /&gt;
TPL_shutter(R_Kinderzimmer2_S)\&lt;br /&gt;
TPL_shutter(R_Kinderzimmer2_W1)\&lt;br /&gt;
TPL_shutter(R_Kinderzimmer2_W2)\&lt;br /&gt;
style(&amp;quot;Erdgeschoss&amp;quot;,&amp;quot;Darkorange&amp;quot;)|&amp;quot;&amp;quot;\&lt;br /&gt;
TPL_shutter(R_Kueche)\&lt;br /&gt;
TPL_shutter(R_W_S)\&lt;br /&gt;
TPL_shutter(R_W_W1)\&lt;br /&gt;
TPL_shutter(R_W_W2)\&lt;br /&gt;
TPL_shutter(R_W_W3)\&lt;br /&gt;
style(&amp;quot;Keller&amp;quot;,&amp;quot;Darkorange&amp;quot;)|&amp;quot;&amp;quot;\&lt;br /&gt;
TPL_shutter(R_Keller)\&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;Ergebnis des Anwendungsbeispiels in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable Rollladen.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;Anzahl der Tage bis zur &#039;&#039;&#039;Abfall-Entsorgung&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Mit Hilfe des Kalender-Moduls werden die verbleibenden Tage bis zur Abfall-Entsorgung der jeweiligen Tonne berechnet und mit Hilfe von uiTable visualisiert. Wenn der Tag der Entsorgung bevorsteht, wird er farbig gekennzeichnet. Vorausgesetzt wird die Definition des Kalenders namens &#039;cal&#039; mit Hilfe des Moduls [[Calendar]]. Dieser muss die Termine der Abfallentsorgung der Tonnen beinhalten. Im Beispiel wird nach Stichwörtern: &amp;quot;Altpapier&amp;quot;, &amp;quot;Restmüll&amp;quot;, &amp;quot;Bio&amp;quot;, &amp;quot;Gelber&amp;quot; und &amp;quot;Grünschnitt&amp;quot; im Kalender gesucht. &lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* FHEM-Modul [[Calendar]]&lt;br /&gt;
* ui_Table Funktion [[DOIF/uiTable Schnelleinstieg#Icon-Darstellung mit Text mit Hilfe der Funktion icon_label|icon_label]]&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Abfall DOIF subs {\&lt;br /&gt;
  ## Die Funktion &#039;days&#039; sucht nach dem Ereignis $event im Kalender und berechnet die Anzahl der verbleibenden Tage und legt sie im entsprechendem Reading $reading des DOIF-Moduls ab\&lt;br /&gt;
  sub days \&lt;br /&gt;
  {\&lt;br /&gt;
    my ($event,$reading)=@_;;\&lt;br /&gt;
    set_Reading($reading,fhem(&#039;get cal events timeFormat:&amp;quot;%j&amp;quot; filter:field(summary)=~&amp;quot;&#039;.$event.&#039;&amp;quot; limit:count=1,from=0 format:custom=&amp;quot;$T1&amp;quot;&#039;)-::strftime (&#039;%j&#039;, localtime()),1)\&lt;br /&gt;
  }\&lt;br /&gt;
  ## Die Funktion &#039;update&#039; bestimmt die verbleibenden Tage mit Hilfe der obigen Funktion &#039;days&#039; für die jeweiligen Tonnen\&lt;br /&gt;
  sub update\&lt;br /&gt;
  {\&lt;br /&gt;
    days(&amp;quot;Altpapier&amp;quot;,&amp;quot;altpapier&amp;quot;);;days(&amp;quot;Restmüll&amp;quot;,&amp;quot;restmuell&amp;quot;);;days(&amp;quot;Bio&amp;quot;,&amp;quot;bio&amp;quot;);;days(&amp;quot;Gelber&amp;quot;,&amp;quot;gelbe_tonne&amp;quot;);;days(&amp;quot;Grünschnitt&amp;quot;,&amp;quot;gruenschnitt&amp;quot;);;\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
## Beim Start, um 02:00 Uhr und 08:00 Uhr wird zeitverzögert die obige Funktion &#039;update&#039; aufgerufen\&lt;br /&gt;
init {[02:00];;[08:00];;set_Exec(&amp;quot;Timer&amp;quot;,60,&#039;update()&#039;);;\&lt;br /&gt;
}&lt;br /&gt;
attr Abfall uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
  $TC{0..4}=&amp;quot;align=&#039;center&#039;&amp;quot;;;\&lt;br /&gt;
  $SHOWNOSTATE=1;;\&lt;br /&gt;
 \&lt;br /&gt;
  ## die Funktion &#039;ic&#039; benutzt die Funktion &#039;icon_label&#039; für die Darstellung des Icons, abhängig von der Anzahl der Tage wird die Anzahl in grün bzw. rot eingefärbt \&lt;br /&gt;
  sub ic\&lt;br /&gt;
  {\&lt;br /&gt;
    my ($icon,$days)=@_;;\&lt;br /&gt;
    icon_label($icon,$days,&amp;quot;white&amp;quot;,$days &amp;gt; 1 ? &amp;quot;green&amp;quot;:&amp;quot;red&amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
}\&lt;br /&gt;
## Tabellendefinition, die einzelnen Tonnen werden mit Hilfe der obigen Funkton &#039;ic&#039; dargestellt\&lt;br /&gt;
\&lt;br /&gt;
ic (&amp;quot;Abfalltonne-Recycling-Logo\@yellow&amp;quot;,[$SELF:gelbe_tonne])|\&lt;br /&gt;
ic (&amp;quot;Abfalltonne-Recycling-Logo\@blue&amp;quot;,[$SELF:altpapier])|\&lt;br /&gt;
ic (&amp;quot;Abfalltonne\@gray&amp;quot;,[$SELF:restmuell])|\&lt;br /&gt;
ic (&amp;quot;Abfalltonne-Recycling-Logo\@green&amp;quot;,[$SELF:bio])|\&lt;br /&gt;
ic (&amp;quot;Gartenabfall\@green&amp;quot;,[$SELF:gruenschnitt])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:Anwendungsbeispiel Abfall.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;Visualisierung: &#039;&#039;&#039;offene Fenster&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Alle offenen Fenster werden aufgelistet und mit entsprechendem Icon visualisiert.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* Attribut {{Link2CmdRef|Anker=DOIF_DOIF_Readings|Lang=de|Label=DOIF_Readings}}&lt;br /&gt;
* DOIF-{{Link2CmdRef|Anker=DOIF_aggregation|Lang=de|Label=Aggregationsfunktionen}}&lt;br /&gt;
* uiTable-Funktion [[DOIF/uiTable Schnelleinstieg#Icon-Darstellung mit Hilfe der Funktion icon|icon]]&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_windows DOIF ## Visualisierung offener Fenster, Fenster-Devices enden mit &amp;quot;Fenster&amp;quot; im Namen&lt;br /&gt;
attr di_uiTable_windows DOIF_Readings windows:[@as(&amp;lt;br&amp;gt;)&amp;quot;Fenster$&amp;quot;:state:&amp;quot;open&amp;quot;,&amp;quot;keine&amp;quot;]&lt;br /&gt;
attr di_uiTable_windows uiTable {package ui_Table;;}\&lt;br /&gt;
icon([$SELF:windows],&amp;quot;fts_window_1w_open\@DarkOrange&amp;quot;,&amp;quot;fts_window_1w&amp;quot;,&amp;quot;.*&amp;quot;,&amp;quot;keine&amp;quot;)|[$SELF:windows]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable windows closed.png|mini|ohne]]&lt;br /&gt;
[[Datei:UiTable windows open.png|mini|ohne]]&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;Visualisierung: &#039;&#039;&#039;aktuelle Wetterlage&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Regenrader animiert, aktuelle Temperatur und Feuchte vom Sensor, aktuelle Wetterlage sowie Wettervorhersage der nächsten Tage. Über entsprechende Weblinks werden Bilder aus dem WWW in der Tabelle visualisiert. Im Gegensatz zu lokalen Sensoren, muss für die Aktualisierung der WWW-Elemente in der jeweiligen Webinstanz (FHEMWEB) das refresh-Attribut gesetzt werden. &lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* DWD [https://www.dwd.de/DE/Home/home_node.html Homepage]&lt;br /&gt;
* Regenradar [https://www.dwd.de/DE/wetter/wetterundklima_vorort/_node.html Radarfilm BRD]&lt;br /&gt;
* aktuelles Wetter [https://www.dwd.de/DE/wetter/wetterundklima_vorort/nordrhein-westfalen/nrw_node.html NRW]&lt;br /&gt;
* Wetteronline [https://www.wetteronline.de/wetter-widget eignes Widget]&lt;br /&gt;
* &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_uiTable_wetter DOIF ##&lt;br /&gt;
attr di_uiTable_wetter uiTable {\&lt;br /&gt;
 package ui_Table;;\&lt;br /&gt;
 $TC{1}=&amp;quot;align=&#039;center&#039;&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
## das Attribut &#039;refresh&#039; der Webinstanz für ein Wandtablet wurde auf 900 gesetzt, damit die Bilder alle 15 Minuten aktualisiert werden \&lt;br /&gt;
## Tabellendefinition\&lt;br /&gt;
\&lt;br /&gt;
## Regenradar BRD\&lt;br /&gt;
&#039;&amp;lt;img src=&amp;quot;https://www.dwd.de/DWD/wetter/radar/radfilm_brd_akt.gif&amp;quot; height=&amp;quot;365px&amp;quot; width=&amp;quot;365px&amp;quot;&amp;gt;&#039;|\&lt;br /&gt;
\&lt;br /&gt;
## Aktuelle Temperatur und Feuchtigkeit vom lokalen sensor\&lt;br /&gt;
temp([Aussensensor:temperature],40),hum ([Aussensensor:humidity],30),\&lt;br /&gt;
\&lt;br /&gt;
## aktuelle Wetterlage NRW\&lt;br /&gt;
&amp;quot;&amp;lt;img src =&#039;https://www.dwd.de/DE/wetter/wetterundklima_vorort/nordrhein-westfalen/_functions/bildgalerie/wetter_aktuell.jpg?view=nasImage&amp;amp;nn=561200&#039; height=&#039;255px&#039; width=&#039;255px&#039;&amp;gt;&amp;quot;|\&lt;br /&gt;
\&lt;br /&gt;
## Wettervorhersage\&lt;br /&gt;
&amp;quot;&amp;lt;iframe marginheight=&#039;0&#039; marginwidth=&#039;0&#039; scrolling=&#039;no&#039; width=&#039;300&#039; height=&#039;365&#039; name=&#039;FC3&#039; style=&#039;border:1px solid;;border-color:#00537f;;&#039; src=&#039;https://api.wetteronline.de/wetterwidget?gid=x0677&amp;amp;modeid=FC3&amp;amp;seourl=juelich&amp;amp;locationname=Jülich&amp;amp;lang=de&#039;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;quot;\&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable wetter.png|600px|links]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;Visualisierung: &#039;&#039;&#039;Wetterstation&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Die vorgestellte Lösung funktioniert ohne Anmeldung beim Wetterdienst und ohne Nutzung von API.&lt;br /&gt;
Über den Wetterdienst: https://www.wunderground.com/ werden sehr viele private Wifi-Wetterstationen eingebunden. Das kann man sich zunutze machen, indem man zunächst in seiner Umgebung nach Wetterstationen des Dienstes sucht - oft findet man im Umkreis von wenigen Kilometern schon einige Stationen, die rege Wetterdaten liefern. Danach definiert man über HTTPMOD seine Station und visualisiert diese anschließend.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* Wunderground [https://wunderground.com/ Homepage]&lt;br /&gt;
* svg-Funktion [https://wiki.fhem.de/wiki/DOIF/uiTable_Schnelleinstieg#Anzeige_eines_Werteverlaufs_und_des_aktuellen_Wertes_mit_Hilfe_der_SVG-Funktion_card card]&lt;br /&gt;
* svg-Funktionen [https://wiki.fhem.de/wiki/DOIF/uiTable_Schnelleinstieg#icon_ring-Funktionen icon_ring]&lt;br /&gt;
}}&lt;br /&gt;
Definition einer Station in der Nachbarschaft. &amp;lt;StationsID&amp;gt; muss gegen die korrekte Stationsnummer ersetzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Wetter HTTPMOD https://www.wunderground.com/dashboard/pws/&amp;lt;StationsID&amp;gt;&lt;br /&gt;
attr Wetter enableControlSet 1&lt;br /&gt;
attr Wetter reading01Name Wind&lt;br /&gt;
attr Wetter reading01Regex wu-unit .{109}&amp;gt;(\d+\.\d)&lt;br /&gt;
attr Wetter reading02Name Windboeen&lt;br /&gt;
attr Wetter reading02Regex wu-unit-speed .{109}&amp;gt;(\d+\.\d)&lt;br /&gt;
attr Wetter reading03Name Windrichtung&lt;br /&gt;
attr Wetter reading03Regex (\d+)deg\).{84}Wind-Marker&lt;br /&gt;
attr Wetter reading04Name Regen&lt;br /&gt;
attr Wetter reading04Regex wu-unit-rainRate .{109}&amp;gt;(\d+\.\d\d)&lt;br /&gt;
attr Wetter reading05Name RegenGesamt&lt;br /&gt;
attr Wetter reading05Regex wu-unit-rain .{109}&amp;gt;(\d+\.\d\d)&lt;br /&gt;
attr Wetter reading06Name Temperatur&lt;br /&gt;
attr Wetter reading06Regex wu-unit-temperature .{127}&amp;gt;(\d+.\d)&lt;br /&gt;
attr Wetter reading07Name Feuchtigkeit&lt;br /&gt;
attr Wetter reading07Regex wu-unit-humidity .{109}&amp;gt;(\d\d)&lt;br /&gt;
attr Wetter reading08Name UV&lt;br /&gt;
attr Wetter reading08Regex UV&amp;lt;.{268}&amp;gt;(\d)&lt;br /&gt;
attr Wetter reading09Name Luftdruck&lt;br /&gt;
attr Wetter reading09Regex PRESSURE&amp;lt;.{285}&amp;gt;(\d+.\d+)&lt;br /&gt;
attr Wetter reading10Name TemperaturGefuehlt&lt;br /&gt;
attr Wetter reading10Regex wu-unit is-degree-visible .{109}&amp;gt;(\d+.\d)&lt;br /&gt;
attr Wetter reading11Name TaupunktTemp&lt;br /&gt;
attr Wetter reading11Regex DEWPOINT.{306}&amp;gt;(\d+.\d)&lt;br /&gt;
attr Wetter reading12Name Sonnenstrahlung&lt;br /&gt;
attr Wetter reading12Regex Solar radiation&amp;lt;.{549}&amp;gt;(\d+.\d+)&lt;br /&gt;
attr Wetter timeout 10&lt;br /&gt;
attr Wetter userReadings WindKm {sprintf(&amp;quot;%1.1f&amp;quot;,ReadingsVal($name,&amp;quot;Wind&amp;quot;,0)*1.60934)},\&lt;br /&gt;
WindboeenKm {sprintf(&amp;quot;%1.1f&amp;quot;,ReadingsVal($name,&amp;quot;Windboeen&amp;quot;,0)*1.60934)},\&lt;br /&gt;
WindrichtungGrad {ReadingsVal($name,&amp;quot;Windrichtung&amp;quot;,0)-180},\&lt;br /&gt;
RegenMm {ReadingsVal($name,&amp;quot;Regen&amp;quot;,0)*25.4},\&lt;br /&gt;
RegenGesamtMm {ReadingsVal($name,&amp;quot;RegenGesamt&amp;quot;,0)*25.4},\&lt;br /&gt;
TemperaturC {sprintf(&amp;quot;%1.1f&amp;quot;,(ReadingsVal($name,&amp;quot;Temperatur&amp;quot;,0)-32)*5/9)},\&lt;br /&gt;
TaupunktTempC {sprintf(&amp;quot;%1.1f&amp;quot;,(ReadingsVal($name,&amp;quot;TaupunktTemp&amp;quot;,0)-32)*5/9)},\&lt;br /&gt;
LuftdruckHpa {sprintf(&amp;quot;%d&amp;quot;,ReadingsVal($name,&amp;quot;Luftdruck&amp;quot;,0)*33.8639)},\&lt;br /&gt;
TemperaturGefuehltC {sprintf(&amp;quot;%1.1f&amp;quot;,(ReadingsVal($name,&amp;quot;TemperaturGefuehlt&amp;quot;,0)-32)*5/9)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun erfolgt die Visualisierung der Daten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_Wetter_ring DOIF ##&lt;br /&gt;
attr di_Wetter_ring uiTable {package ui_Table;;}\&lt;br /&gt;
\&lt;br /&gt;
icon_temp_hum_ring(&amp;quot;temp_outside&amp;quot;,[Wetter:TemperaturC],[Wetter:Feuchtigkeit],undef,undef,150)|\&lt;br /&gt;
icon_temp_ring (&amp;quot;temp_windchill&amp;quot;,[Wetter:TemperaturGefuehltC],undef,undef,150) |\&lt;br /&gt;
icon_temp_ring (&amp;quot;temperature_humidity&amp;quot;,[Wetter:TaupunktTempC],undef,undef,150) |\&lt;br /&gt;
icon_ring2([Wetter:WindKm] &amp;gt; 0 ? &amp;quot;wind&amp;quot;.&amp;quot;,1,0,0,&amp;quot;.[Wetter:WindrichtungGrad]:&amp;quot;no_wind&amp;quot;,[Wetter:WindKm],0,50,120,0,&amp;quot;km/h&amp;quot;,150,undef,1,[Wetter:WindboeenKm],0,50,120,0,&amp;quot;km/h&amp;quot;,undef,1) |\&lt;br /&gt;
icon_ring2(&amp;quot;weather_rain_gauge&amp;quot;,[Wetter:RegenMm],0,10,180,270,&amp;quot;mm/h&amp;quot;,150,undef,1,[Wetter:RegenGesamtMm],0,50,180,270,&amp;quot;mm&amp;quot;,undef,1)|\&lt;br /&gt;
icon_ring2(&amp;quot;sani_solar&amp;quot;,[Wetter:UV],0,10,100,30,&amp;quot;UV&amp;quot;,150,undef,0,[Wetter:Sonnenstrahlung],0,1000,100,30,&amp;quot;Watt/m²&amp;quot;,undef,0)|\&lt;br /&gt;
icon_ring (&amp;quot;weather_barometric_pressure&amp;quot;,[Wetter:LuftdruckHpa],980,1047,0,120,&amp;quot;hPa&amp;quot;,0,150)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable ringwetter.png|600px|links]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier ein Beispiel der Visualisierung mit Verlauf der letzten drei Tage mit Hilfe der svg-Funktion &#039;&#039;&#039;card&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_Wetter DOIF ##&lt;br /&gt;
attr di_Wetter icon weather_wind&lt;br /&gt;
attr di_Wetter uiTable {package ui_Table;;}\&lt;br /&gt;
##  card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness)\&lt;br /&gt;
\&lt;br /&gt;
card([Wetter:TemperaturC:col3d],&amp;quot;Außentemperatur&amp;quot;,&amp;quot;temp_outside&amp;quot;,-10,60,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue)|\&lt;br /&gt;
card([Wetter:TemperaturGefuehltC:col3d],&amp;quot;gefühlte Temperatur&amp;quot;,&amp;quot;temp_windchill&amp;quot;,-10,60,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue)|\&lt;br /&gt;
card([Wetter:TaupunktTempC:col3d],&amp;quot;Taupunkttemperatur&amp;quot;,&amp;quot;temperature_humidity&amp;quot;,-10,60,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue)|\&lt;br /&gt;
card([Wetter:Feuchtigkeit:col3d],&amp;quot;Außenfeuchtigkeit&amp;quot;,&amp;quot;temperature_humidity&amp;quot;,0,100,undef,undef,&amp;quot;%&amp;quot;,\&amp;amp;hum_hue)|\&lt;br /&gt;
card([Wetter:WindKm:col3d],&amp;quot;Wind&amp;quot;,[Wetter:WindKm] &amp;gt; 0 ? &amp;quot;wind&amp;quot;.&amp;quot;,1,0,0,&amp;quot;.[Wetter:WindrichtungGrad]:&amp;quot;no_wind&amp;quot;,0,30,90,30,&amp;quot;km/h&amp;quot;,undef,1)\&lt;br /&gt;
card([Wetter:WindboeenKm:col3d],&amp;quot;Windböen&amp;quot;,&amp;quot;weather_wind&amp;quot;,0,30,90,30,&amp;quot;km/h&amp;quot;,undef,1)|\&lt;br /&gt;
card([Wetter:RegenMm:col3d],&amp;quot;Regen&amp;quot;,&amp;quot;weather_rain_gauge&amp;quot;,0,10,180,270,&amp;quot;mm/h&amp;quot;)|\&lt;br /&gt;
card([Wetter:RegenGesamtMm:col3d],&amp;quot;Regengesamt&amp;quot;,&amp;quot;weather_rain_gauge&amp;quot;,0,50,180,270,&amp;quot;mm&amp;quot;)|\&lt;br /&gt;
##card([Wetter:UV:col3d],&amp;quot;UV-Strahlung&amp;quot;,&amp;quot;sani_solar&amp;quot;,0,7,100,30,&amp;quot;UV&amp;quot;,undef,0)|\&lt;br /&gt;
card([Wetter:Sonnenstrahlung:col3d],&amp;quot;Sonnenstrahlung&amp;quot;,&amp;quot;sani_solar&amp;quot;,0,1000,30,90,&amp;quot;Watt/m²&amp;quot;,undef,0)|\&lt;br /&gt;
card([Wetter:LuftdruckHpa:col3d],&amp;quot;Luftdruck&amp;quot;,&amp;quot;weather_barometric_pressure&amp;quot;,980,1047,30,90,&amp;quot;hPa&amp;quot;,undef,0)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable svgwetter.png|600px|links]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ohne Angabe der Überschrift (undef für $header setzen) lässt sich eine kompaktere Darstellung erzielen:&lt;br /&gt;
&lt;br /&gt;
[[Datei:UiTable svgwetteroh.png|600px|links]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;Visualisierung: &#039;&#039;&#039;aktueller Spritpreis&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Der aktuelle Spritpreis einer Tankstelle wird ermittelt und mit seinem zeitlichen Verlauf visualisiert.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* svg-Funktion [[DOIF/uiTable_Schnelleinstieg#ring-Funktionen|ring]]&lt;br /&gt;
* svg-Funktion [[DOIF/uiTable_Schnelleinstieg#Anzeige_eines_Werteverlaufs_und_des_aktuellen_Wertes_mit_Hilfe_der_SVG-Funktion_card|card]]&lt;br /&gt;
* Tankstelle bestimmen [https://www.clever-tanken.de/ Clever tanken]&lt;br /&gt;
* Modul [[HTTPMOD]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Zunächst wird ein HTTPMOD-Modul für den aktuellen Spritpreis definiert, dabei ist &amp;lt;Stations-ID&amp;gt; durch die ID der Tankstelle zu ersetzen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Tankstelle HTTPMOD http://www.clever-tanken.de/tankstelle_details/&amp;lt;Stations-ID&amp;gt; 300&lt;br /&gt;
attr Tankstelle devStateIcon {ui_Table::ring(ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Diesel&amp;quot;,0),1.00,1.40,120,0,&amp;quot;Diesel&amp;quot;,90,undef,2).&amp;quot; &amp;quot;.ui_Table::ring(ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SuperE5&amp;quot;,0),1.10,1.60,120,0,&amp;quot;E5&amp;quot;,90,undef,2)}&lt;br /&gt;
attr Tankstelle enableControlSet 1&lt;br /&gt;
attr Tankstelle event-on-change-reading .*&lt;br /&gt;
attr Tankstelle group Spritpreise&lt;br /&gt;
attr Tankstelle reading01Name Diesel&lt;br /&gt;
attr Tankstelle reading01Regex &amp;quot;current-price-1&amp;quot;&amp;gt;(\d.\d{2})&lt;br /&gt;
attr Tankstelle reading02Name SuperE5&lt;br /&gt;
attr Tankstelle reading02Regex &amp;quot;current-price-2&amp;quot;&amp;gt;(\d.\d{2})&lt;br /&gt;
attr Tankstelle room Spritpreise&lt;br /&gt;
attr Tankstelle timeout 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:Di uiTable Tankstelle.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
Visualisierung der Preisentwicklung der letzten 24 Stunden: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod sprit DOIF ##&lt;br /&gt;
attr sprit uiTable {package ui_Table;;}\&lt;br /&gt;
card([Tankstelle:Diesel:col24],&amp;quot;Diesel&amp;quot;,&amp;quot;fuel&amp;quot;,&amp;quot;1.00&amp;quot;,&amp;quot;1.40&amp;quot;,120,0,&amp;quot;Diesel €&amp;quot;,undef,&amp;quot;2&amp;quot;,&amp;quot;,,1&amp;quot;)\&lt;br /&gt;
card([Tankstelle:SuperE5:col24],&amp;quot;Super E5&amp;quot;,&amp;quot;fuel&amp;quot;,&amp;quot;1.10&amp;quot;,&amp;quot;1.60&amp;quot;,120,0,&amp;quot;Super €&amp;quot;,undef,&amp;quot;2&amp;quot;,&amp;quot;,,1&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:Di uiTable sprit.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;Visualisierung: &#039;&#039;&#039;aktuelle Corona-7-Tage-Inzidenz&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Die aktuellen Inzidenzwerte werden vom RKI ausgelesen und deren Verlauf visualisiert.&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* svg-Funktion [[DOIF/uiTable_Schnelleinstieg#ring-Funktionen|ring]]&lt;br /&gt;
* svg-Funktion [[DOIF/uiTable_Schnelleinstieg#Anzeige_eines_Werteverlaufs_und_des_aktuellen_Wertes_mit_Hilfe_der_SVG-Funktion_card|card]]&lt;br /&gt;
* Modul [[JsonMod]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Zunächst wird ein JsonMod Device für das Auslesen der Inzidenzzahlen definiert. Die gewünschten Regionen müssen für eigene Bedürfnisse angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod RKI7 JsonMod https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_Landkreisdaten/FeatureServer/0/query?where=1%3D1&amp;amp;outFields=last_update,cases7_per_100k,BEZ,BEM,GEN,BL,county&amp;amp;returnGeometry=false&amp;amp;outSR=4326&amp;amp;f=json&lt;br /&gt;
attr RKI7 readingList multi(jsonPath(&amp;quot;\$.features[?(\@.attributes.GEN in [&#039;Städteregion Aachen&#039;, &#039;Düren&#039;, &#039;Heinsberg&#039;])]&amp;quot;), property(&#039;attributes.GEN&#039;), sprintf(&#039;%.1f&#039;, property(&#039;attributes.cases7_per_100k&#039;)));;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Visualisierung der Inzidenzzahlen der letzten sieben Tage: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_corona DOIF ##&lt;br /&gt;
attr di_corona uiTable {package ui_Table}\&lt;br /&gt;
card([RKI7:Duren:col1w],&amp;quot;Düren&amp;quot;,&amp;quot;coronavirus&amp;quot;,0,200,120,0,&amp;quot;Fälle&amp;quot;)|\&lt;br /&gt;
card([RKI7:Heinsberg:col1w],&amp;quot;Heinsberg&amp;quot;,&amp;quot;coronavirus&amp;quot;,0,200,120,0,&amp;quot;Fälle&amp;quot;)|\&lt;br /&gt;
card([RKI7:Stadteregion_Aachen:col1w],&amp;quot;Aachen&amp;quot;,&amp;quot;coronavirus&amp;quot;,0,200,120,0,&amp;quot;Fälle&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:uiTable_Inzidenz.png|600px|links]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039; Visualisierung und Steuerung: &#039;&#039;&#039;Heiztherme&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Im folgenden Beispiel wurde eine Heiztherme über einen ebus-Adapter in FHEM eingebunden. Die Heizungsdaten werden über MQTT ausgelesen und anschließend visualisiert. Die vorgestellten Visualisierungsbeispiele können ebenso im funktionslosen DOIF mit Hilfe des uiTable-Attriutes auf bereits existierende Readings des eigenen Systems angewendet werden. &lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* svg-Funktion [[DOIF/uiTable_Schnelleinstieg#icon_ring-Funktionen|icon_ring]]&lt;br /&gt;
* svg-Funktion [[DOIF/uiTable_Schnelleinstieg#Anzeige_eines_Werteverlaufs_und_des_aktuellen_Wertes_mit_Hilfe_der_SVG-Funktion_card|card]]&lt;br /&gt;
* Commandref [https://fhem.de/commandref_DE.html#DOIF_Perl_Modus DOIF Perl-Modus]&lt;br /&gt;
* ebus-Adapter [https://ebusd.de/ ebusd]&lt;br /&gt;
* ebus-Wiki [[EBUS|ebus]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Definition eines MQTT2-Devices für die Kommunikation mit der Therme über einen ebus-Adapter.&lt;br /&gt;
&lt;br /&gt;
Im diesem Fall wurde eine Vaillanttherme eingebunden, die meisten Readings wurden automatisch vom MQTT2-Server angelegt. Die Anbindung ist gerätespezifisch und unterscheidet sich je nach Gerättyp.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod vaillant MQTT2_DEVICE ebusd_bai&lt;br /&gt;
attr vaillant IODev MQTT2_FHEM_Server&lt;br /&gt;
attr vaillant devStateStyle style=&amp;quot;text-align:left&amp;quot;&lt;br /&gt;
attr vaillant event-on-change-reading .*&lt;br /&gt;
attr vaillant group Ebus&lt;br /&gt;
attr vaillant icon sani_boiler_temp&lt;br /&gt;
attr vaillant jsonMap Status01_0_value:Vorlauf Status01_0_name:0\&lt;br /&gt;
Status01_1_value:Ruecklauf Status01_1_name:0\&lt;br /&gt;
Status01_2_value:Aussentemp Status01_2_name:0\&lt;br /&gt;
Status01_3_value:Warmwasser Status01_3_name:0\&lt;br /&gt;
Status01_4_value:WWSpeicher Status01_4_name:0\&lt;br /&gt;
Status01_5_value:Pumpenstatus Status01_5_name:0\&lt;br /&gt;
Flame_0_value:Flame Flame_0_name:0\&lt;br /&gt;
Storageloadpump_percent0_value:Storageloadpump\&lt;br /&gt;
FlowTempDesired_temp_value:VorlaufSoll\&lt;br /&gt;
Hc1HeatCurve_0_value:HeizKennlinie Hc1HeatCurve_0_name:0\&lt;br /&gt;
HolidayEndPeriod_hto_value:FerienEnde\&lt;br /&gt;
HolidayStartPeriod_hfrom_value:FerienBeginn\&lt;br /&gt;
PumpPower_0_value:PumpenLeistung PumpPower_0_name:0\&lt;br /&gt;
PrimaryCircuitFlowrate_uin100_value:Umlaufmenge\&lt;br /&gt;
z1DayTemp_tempv_value:TagSolltemp\&lt;br /&gt;
z1NightTemp_tempv_value:NachtSolltemp\&lt;br /&gt;
FanSpeed_0_value:LuefterDrehzahl FanSpeed_0_name:0\&lt;br /&gt;
WaterPressure_pressv_value:Wasserdruck\&lt;br /&gt;
z1OpMode_opmode_value:Heizmodus&lt;br /&gt;
attr vaillant model eBus_bai_jsonmap&lt;br /&gt;
attr vaillant readingList ebusd/bai/PumpHours:.* { json2nameValue($EVENT, &#039;PumpHours_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/WPPostrunTime:.* { json2nameValue($EVENT, &#039;WPPostrunTime_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PowerValue:.* { json2nameValue($EVENT, &#039;PowerValue_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/StorageExitTemp:.* { json2nameValue($EVENT, &#039;StorageExitTemp_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/global/version:.* version\&lt;br /&gt;
ebusd/global/running:.* running\&lt;br /&gt;
ebusd/scan\x5c\x2e08/:.* { json2nameValue($EVENT, &#039;scan.08_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/scan\x5c\x2e08/id:.* { json2nameValue($EVENT, &#039;id_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/global/uptime:.* uptime\&lt;br /&gt;
ebusd/global/signal:.* signal\&lt;br /&gt;
ebusd/scan\x5c\x2e15/:.* { json2nameValue($EVENT, &#039;scan.15_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/scan\x5c\x2e15/id:.* { json2nameValue($EVENT, &#039;id_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/FanSpeed:.* { json2nameValue($EVENT, &#039;FanSpeed_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PumpPower:.* { json2nameValue($EVENT, &#039;PumpPower_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/broadcast/vdatetime:.* { json2nameValue($EVENT, &#039;vdatetime_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/broadcast/outsidetemp:.* { json2nameValue($EVENT, &#039;outsidetemp_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/DateTime:.* { json2nameValue($EVENT, &#039;DateTime_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/global/updatecheck:.* updatecheck\&lt;br /&gt;
ebusd/bai/DCFTimeDate:.* { json2nameValue($EVENT, &#039;DCFTimeDate_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PumpPowerDesired:.* { json2nameValue($EVENT, &#039;PumpPowerDesired_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/HwcImpellorSwitch:.* { json2nameValue($EVENT, &#039;HwcImpellorSwitch_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/ReturnTemp:.* { json2nameValue($EVENT, &#039;ReturnTemp_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/HwcStorageTempBottom:.* { json2nameValue($EVENT, &#039;HwcStorageTempBottom_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/HwcTempDesired:.* { json2nameValue($EVENT, &#039;HwcTempDesired_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/FanPWMSum:.* { json2nameValue($EVENT, &#039;FanPWMSum_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/HcHours:.* { json2nameValue($EVENT, &#039;HcHours_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/HoursTillService:.* { json2nameValue($EVENT, &#039;HoursTillService_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PumpHwcFlowNumber:.* { json2nameValue($EVENT, &#039;PumpHwcFlowNumber_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/WP:.* { json2nameValue($EVENT, &#039;WP_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/WaterPressure:.* { json2nameValue($EVENT, &#039;WaterPressure_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PrimaryCircuitFlowrate:.* { json2nameValue($EVENT, &#039;PrimaryCircuitFlowrate_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/Flame:.* { json2nameValue($EVENT, &#039;Flame_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/Storageloadpump:.* { json2nameValue($EVENT, &#039;Storageloadpump_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/Status01:.* { json2nameValue($EVENT, &#039;Status01_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/FlowTempDesired:.* { json2nameValue($EVENT, &#039;FlowTempDesired_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/FrostOverRideTime:.* { json2nameValue($EVENT, &#039;FrostOverRideTime_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/Hc1ActualFlowTempDesired:.* { json2nameValue($EVENT, &#039;Hc1ActualFlowTempDesired_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/Hc1AutoOffMode:.* { json2nameValue($EVENT, &#039;Hc1AutoOffMode_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/Hc1CircuitType:.* { json2nameValue($EVENT, &#039;Hc1CircuitType_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/Hc1HeatCurve:.* { json2nameValue($EVENT, &#039;Hc1HeatCurve_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/HcStorageTempBottom:.* { json2nameValue($EVENT, &#039;HcStorageTempBottom_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/HcStorageTempTop:.* { json2nameValue($EVENT, &#039;HcStorageTempTop_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/HolidayTemp:.* { json2nameValue($EVENT, &#039;HolidayTemp_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/OpMode:.* { json2nameValue($EVENT, &#039;OpMode_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1RoomTemp:.* { json2nameValue($EVENT, &#039;z1RoomTemp_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1SFMode:.* { json2nameValue($EVENT, &#039;z1SFMode_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1OpMode:.* { json2nameValue($EVENT, &#039;z1OpMode_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/Time:.* { json2nameValue($EVENT, &#039;Time_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/EbusVoltage:.* { json2nameValue($EVENT, &#039;EbusVoltage_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/extWP:.* { json2nameValue($EVENT, &#039;extWP_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/FanStarts:.* { json2nameValue($EVENT, &#039;FanStarts_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1NightTemp:.* { json2nameValue($EVENT, &#039;z1NightTemp_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1DayTemp:.* { json2nameValue($EVENT, &#039;z1DayTemp_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/HolidayStartPeriod:.* { json2nameValue($EVENT, &#039;HolidayStartPeriod_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/HolidayEndPeriod:.* { json2nameValue($EVENT, &#039;HolidayEndPeriod_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1Timer.Monday:.* { json2nameValue($EVENT, &#039;z1Timer.Monday_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1Timer.Tuesday:.* { json2nameValue($EVENT, &#039;z1Timer.Tuesday_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1Timer.Wednesday:.* { json2nameValue($EVENT, &#039;z1Timer.Wednesday_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1Timer.Thursday:.* { json2nameValue($EVENT, &#039;z1Timer.Thursday_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1Timer.Friday:.* { json2nameValue($EVENT, &#039;z1Timer.Friday_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1Timer.Sunday:.* { json2nameValue($EVENT, &#039;z1Timer.Sunday_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/700/z1Timer.Saturday:.* { json2nameValue($EVENT, &#039;z1Timer.Saturday_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PrEnergyCountHc1:.* { json2nameValue($EVENT, &#039;PrEnergyCountHc1_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PrEnergyCountHwc1:.* { json2nameValue($EVENT, &#039;PrEnergyCountHwc1_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PrEnergySumHc1:.* { json2nameValue($EVENT, &#039;PrEnergySumHc1_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/PrEnergySumHwc1:.* { json2nameValue($EVENT, &#039;PrEnergySumHwc1_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/FanHours:.* { json2nameValue($EVENT, &#039;FanHours_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/HcHours:.* { json2nameValue($EVENT, &#039;HcHours_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/HwcHours:.* { json2nameValue($EVENT, &#039;HwcHours_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/HcStarts:.* { json2nameValue($EVENT, &#039;HcStarts_&#039;, $JSONMAP) }\&lt;br /&gt;
ebusd/bai/HwcStarts:.* { json2nameValue($EVENT, &#039;HwcStarts_&#039;, $JSONMAP) }&lt;br /&gt;
attr vaillant setList HeizKennlinie:selectnumbers,0,.1,2,1,lin ebusd/700/Hc1HeatCurve/set $EVTPART1\&lt;br /&gt;
TagSolltemp:selectnumbers,15,1,25,1,lin ebusd/700/z1DayTemp/set $EVTPART1\&lt;br /&gt;
NachtSolltemp:selectnumbers,15,1,25,1,lin ebusd/700/z1NightTemp/set $EVTPART1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Definition eines DOIF-Devices zur Steuerung der Therme und Visualisierung der Daten. Es werden Readings und Befehle genutzt, die durch den MQTT2-Server der obigen Definition zur Verfügung gestellt werden. Einzelne Heizungswerte werden in bestimmten Intervallen über den publish-Befehl ausgelesen. Die Temperaturen der Zirkulation, des Vorlaufs und des Rücklaufs werden außerhalb der Therme mit 1-wire-Temperatursensoren über WLAN-ESP-Easy ausgelesen. Die Definition des Layouts über das Attribut uiTable ist unabhängig vom Auslesen der Werte, sie bezieht sich lediglich auf vorhandene Readings, die visualisiert werden sollen. Das Layout kann ebenso auf Readings aus anderen Devices der eigenen FHEM-Umgebung anpasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod di_vaillant DOIF ##{[+00:01];;foreach (qw(FanSpeed Flame PumpPower Storageloadpump PrimaryCircuitFlowrate FlowTempDesired PumpHours HcHours HcPumpStarts)) {fhem_set(&amp;quot;MQTT2_FHEM_Server publish ebusd/bai/$_/get&amp;quot;)}}\&lt;br /&gt;
\&lt;br /&gt;
{[+[1]:01];;foreach (qw(PrEnergySumHc1 PrEnergySumHwc1 HcHours HwcHours z1OpMode WaterPressure z1NightTemp z1DayTemp Hc1HeatCurve HwcLockTime HolidayStartPeriod HolidayEndPeriod)) {fhem_set(&amp;quot;MQTT2_FHEM_Server publish ebusd/bai/$_/get&amp;quot;)}\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
{[+00:00:30];;foreach (qw(Flame PrimaryCircuitFlowrate)) {fhem_set(&amp;quot;MQTT2_FHEM_Server publish ebusd/bai/$_/get&amp;quot;)}}\&lt;br /&gt;
\&lt;br /&gt;
{[00:01];;foreach (qw(FanHours HcStarts HwcStarts )) {fhem_set(&amp;quot;MQTT2_FHEM_Server publish ebusd/bai/$_/get&amp;quot;)}\&lt;br /&gt;
  set_Reading(&amp;quot;gesamt_hc&amp;quot;,int([?vaillant:PrEnergySumHc1_0_value]/10000)/10,0);;\&lt;br /&gt;
  set_Reading(&amp;quot;gesamt_hwc&amp;quot;,int([?vaillant:PrEnergySumHwc1_0_value]/10000)/10,0);;\&lt;br /&gt;
  set_Reading(&amp;quot;diff_hc&amp;quot;,0,1);;\&lt;br /&gt;
  set_Reading(&amp;quot;diff_hwc&amp;quot;,0,1);;\&lt;br /&gt;
  set_Reading(&amp;quot;diff_h&amp;quot;,0,1)\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
{if ([00:05|WE]) {fhem_set(&amp;quot;MQTT2_FHEM_Server publish ebusd/700/BankHolidayStartPeriod/set $mday.$month.$year&amp;quot;);;fhem_set(&amp;quot;MQTT2_FHEM_Server publish ebusd/700/BankHolidayEndPeriod/set $mday.$month.$year&amp;quot;)}}\&lt;br /&gt;
\&lt;br /&gt;
Timer {\&lt;br /&gt;
fhem_set &amp;quot;MQTT2_FHEM_Server publish ebusd/700/z1Timer.Monday/set 04:00;;09:00;;13:00;;22:00;;-:-;;-:-&amp;quot;\&lt;br /&gt;
fhem_set &amp;quot;MQTT2_FHEM_Server publish ebusd/700/z1Timer.Tuesday/set 04:00;;09:00;;13:00;;22:00;;-:-;;-:-&amp;quot;\&lt;br /&gt;
fhem_set &amp;quot;MQTT2_FHEM_Server publish ebusd/700/z1Timer.Wednesday/set 04:00;;09:00;;13:00;;22:00;;-:-;;-:-&amp;quot;\&lt;br /&gt;
fhem_set &amp;quot;MQTT2_FHEM_Server publish ebusd/700/z1Timer.Thursday/set 04:00;;09:00;;13:00;;22:00;;-:-;;-:-&amp;quot;\&lt;br /&gt;
fhem_set &amp;quot;MQTT2_FHEM_Server publish ebusd/700/z1Timer.Friday/set 04:00;;09:00;;13:00;;22:00;;-:-;;-:-&amp;quot;\&lt;br /&gt;
fhem_set &amp;quot;MQTT2_FHEM_Server publish ebusd/700/z1Timer.Sunday/set 05:00;;10:00;;12:00;;22:30;;-:-;;-:-&amp;quot;\&lt;br /&gt;
fhem_set &amp;quot;MQTT2_FHEM_Server publish ebusd/700/z1Timer.Saturday/set 05:00;;10:00;;12:00;;22:30;;-:-;;-:-&amp;quot;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
diff {\&lt;br /&gt;
 set_Reading(&amp;quot;diff_hc&amp;quot;,int(([vaillant:PrEnergySumHc1_0_value]/100000-get_Reading(&amp;quot;gesamt_hc&amp;quot;,0))*10)/10,1);;\&lt;br /&gt;
 set_Reading(&amp;quot;diff_hwc&amp;quot;,int(([vaillant:PrEnergySumHwc1_0_value]/100000-get_Reading(&amp;quot;gesamt_hwc&amp;quot;,0))*10)/10,1);;\&lt;br /&gt;
 set_Reading(&amp;quot;diff_h&amp;quot;,get_Reading(&amp;quot;diff_hc&amp;quot;)+get_Reading(&amp;quot;diff_hwc&amp;quot;),1);;\&lt;br /&gt;
}\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
attr di_vaillant event-on-change-reading .*&lt;br /&gt;
attr di_vaillant room Ebus&lt;br /&gt;
attr di_vaillant uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
  $TABLE=&#039;text-align:center;;&#039;;;\&lt;br /&gt;
  $SHOWNODEVICELINE = &amp;quot;test9|Damian&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
icon_temp_ring(&amp;quot;temp_outside&amp;quot;,[vaillant:Aussentemp],-15,40,130)|\&lt;br /&gt;
icon_temp_mring(([vaillant:Flame] eq &amp;quot;off&amp;quot;?&amp;quot;sani_boiler_temp\@white&amp;quot;:&amp;quot;sani_boiler_temp\@Darkorange&amp;quot;),[vaillant:Vorlauf],15,70,130)|\&lt;br /&gt;
icon_temp_mring(([vaillant:Pumpenstatus] eq &amp;quot;4&amp;quot; ? &amp;quot;sani_buffer_temp_down\@Darkorange&amp;quot; : &amp;quot;sani_buffer_temp_down\@white&amp;quot;),[vaillant:WWSpeicher],15,70,130)|\&lt;br /&gt;
icon_uring(&amp;quot;0,0,1&amp;quot;,&amp;quot;weather_barometric_pressure&amp;quot;,[vaillant:Wasserdruck],0,3,undef,undef,&amp;quot;bar&amp;quot;,1,130,[(0.8,0,1,60,1.5,120,1.7,60,3,0)],&amp;quot;50,35&amp;quot;)|\&lt;br /&gt;
icon_ring(&amp;quot;sani_floor_heating_neutral&amp;quot;,[vaillant:HcHours_hoursum2_value],0,10000,120,0,&amp;quot;h&amp;quot;,0,130)|\&lt;br /&gt;
icon_ring(&amp;quot;sani_water_tap&amp;quot;,[vaillant:HwcHours_hoursum2_value],0,2000,120,0,&amp;quot;h&amp;quot;,0,130)|\&lt;br /&gt;
\&lt;br /&gt;
icon_ring(&amp;quot;time_graph&amp;quot;,[vaillant:HeizKennlinie],0.4,1,120,0,&amp;quot;HK&amp;quot;,1,130)|\&lt;br /&gt;
icon_temp_mring(&amp;quot;scene_day\@yellow&amp;quot;,[vaillant:TagSolltemp],undef,undef,130)|\&lt;br /&gt;
icon_temp_mring(&amp;quot;scene_night\@#3464eb&amp;quot;,[vaillant:NachtSolltemp],undef,undef,130)\&lt;br /&gt;
&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|&amp;quot;&amp;quot;|widget([vaillant:HeizKennlinie],&amp;quot;selectnumbers,0.4,.1,1,1,lin&amp;quot;,&amp;quot;set&amp;quot;)|widget([vaillant:TagSolltemp],&amp;quot;selectnumbers,15,1,25,1,lin&amp;quot;,&amp;quot;set&amp;quot;)|widget([vaillant:NachtSolltemp],&amp;quot;selectnumbers,15,1,25,1,lin&amp;quot;,&amp;quot;set&amp;quot;)&amp;lt;\&lt;br /&gt;
\&lt;br /&gt;
card([vaillant:Aussentemp:col],&amp;quot;Außentemperatur&amp;quot;,&amp;quot;temp_outside&amp;quot;,-15,35,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue)|\&lt;br /&gt;
card([vaillant:WWSpeicher:col],&amp;quot;WW-Speicher&amp;quot;,([vaillant:Pumpenstatus] eq &amp;quot;4&amp;quot; ? &amp;quot;sani_buffer_temp_down\@Darkorange&amp;quot; : &amp;quot;sani_buffer_temp_down\@white&amp;quot;),15,70,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue)|\&lt;br /&gt;
card([ESPEasy_ESP_Temp_Vorlauf:Temperature:col],&amp;quot;Vorlauf&amp;quot;,([vaillant:Pumpenstatus] eq &amp;quot;on&amp;quot; ? &amp;quot;sani_floor_heating\@Darkorange&amp;quot; : &amp;quot;sani_floor_heating_neutral\@white&amp;quot;),15,70,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue)|\&lt;br /&gt;
card([$SELF:diff_hc:col],&amp;quot;Energie Heizung&amp;quot;,&amp;quot;sani_floor_heating_neutral&amp;quot;,0,100,120,0,&amp;quot;kWh&amp;quot;,undef,1)\&lt;br /&gt;
card([vaillant:Umlaufmenge:col],&amp;quot;Umlaufmenge&amp;quot;,&amp;quot;sani_pump&amp;quot;,0,20,120,0,&amp;quot;l/min&amp;quot;)|\&lt;br /&gt;
card([ESPEasy_ESP_Temp_Zirkulation:Temperature:col],&amp;quot;Zirkulation&amp;quot;,([Zirk] eq &amp;quot;off&amp;quot;?&amp;quot;sani_pump\@white&amp;quot;:&amp;quot;sani_pump\@Darkorange&amp;quot;),15,70,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue)|\&lt;br /&gt;
card([ESPEasy_ESP_Temp_Keller_Ruecklauf:Temperature:col],&amp;quot;Rücklauf&amp;quot;,&amp;quot;sani_floor_heating_neutral\@wite&amp;quot;,15,70,undef,undef,&amp;quot;°C&amp;quot;,\&amp;amp;temp_hue)|\&lt;br /&gt;
card([$SELF:diff_hwc:col],&amp;quot;Energie Warmwasser&amp;quot;,&amp;quot;sani_water_tap&amp;quot;,0,15,120,0,&amp;quot;kWh&amp;quot;,undef,1)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:Di uiTable Heizung.png|600px|links]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;Visualisierung: &#039;&#039;&#039;Anwesenheitsstatus&#039;&#039;&#039;&#039;&#039; ===&lt;br /&gt;
Die aktuelle Anwesenheit von Heimbewohnern wird visualisiert.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Zunächst wird mit Hilfe des Moduls [[FRITZBOX]] ein Device namens &#039;&#039;FritzBox&#039;&#039; erstellt. Dort werden die eingebuchten Smartphones der Bewohner mit Ihren MAC-Adressen in Readings abgelegt. Die folgende Definition wertet aus, ob die angegebenen MAC-Adressen als Readings vorhanden sind und erstellt für jeden Bewohner ein Reading mit den Zuständen on/off. Diese Readings werden dann über das Attribut uiTable visualisiert. Die anwesenden Personen werden farblich markiert. Die Namen der Personen sowie die MAC-Adressen sind fiktiv und müssen den eigenen Angaben entsprechend angepasst werden.&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;nützliche Links&#039;&#039;&#039;&lt;br /&gt;
* [[FRITZBOX|FritzBox-Modul]]&lt;br /&gt;
* ui_Table Funktion [[DOIF/uiTable Schnelleinstieg#Icon-Darstellung mit Text mit Hilfe der Funktion icon_label|icon_label]]&lt;br /&gt;
*[[DOIF/uiTable Schnelleinstieg#uiTable-Templates|uiTable-Templates]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod myHome DOIF {\&lt;br /&gt;
 set_Reading_Begin;;\&lt;br /&gt;
  set_Reading_Update(&amp;quot;Ernie&amp;quot;,[FritzBox:mac_12_34_E0_00_CD_E4] ? &amp;quot;on&amp;quot;:&amp;quot;off&amp;quot;);;\&lt;br /&gt;
  set_Reading_Update(&amp;quot;Bert&amp;quot;, [FritzBox:mac_02_08_02_07_30_E3] ? &amp;quot;on&amp;quot;:&amp;quot;off&amp;quot;);;\&lt;br /&gt;
  set_Reading_Update(&amp;quot;Grobi&amp;quot;, [FritzBox:mac_00_08_01_0B_00_E7] ? &amp;quot;on&amp;quot;:&amp;quot;off&amp;quot;);; \&lt;br /&gt;
  set_Reading_Update(&amp;quot;Kermit&amp;quot;, [FritzBox:mac_01_30_A9_72_02_E3] ? &amp;quot;on&amp;quot;:&amp;quot;off&amp;quot;);; \&lt;br /&gt;
 set_Reading_End(1);;\&lt;br /&gt;
}&lt;br /&gt;
attr myHome checkReadingEvent 0&lt;br /&gt;
attr myHome uiTable {\&lt;br /&gt;
  package ui_Table;;\&lt;br /&gt;
  $SHOWNOSTATE=1;;\&lt;br /&gt;
  $TC{0..4}=&amp;quot;align=&#039;center&#039;&amp;quot;;;\&lt;br /&gt;
}\&lt;br /&gt;
## Template-Definition für die Visualisierung eines Bewohners mit Hilfe des Icons fa__508\&lt;br /&gt;
DEF TPL_person (icon_label([$SELF:$1] eq &amp;quot;on&amp;quot; ? &amp;quot;fa__508\@DarkOrange&amp;quot;:&amp;quot;fa__508&amp;quot;,&amp;quot;$1&amp;quot;,&amp;quot;#e67e00&amp;quot;,&amp;quot;white&amp;quot;,-10))\&lt;br /&gt;
\&lt;br /&gt;
## Darstellung der Bewohner mit Hilfe des obigen Templates\&lt;br /&gt;
TPL_person(Ernie)|TPL_person(Bert)|TPL_person(Grobi)|TPL_person(Kermit)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ergebnis der Beispieldefinition in der Webansicht:&#039;&#039;&lt;br /&gt;
[[Datei:UiTable myHome.png|ohne|mini]]&lt;br /&gt;
&lt;br /&gt;
=== Weitere Anwendungsbeispiele zur Automatisierung ===&lt;br /&gt;
* siehe [[DOIF/Automatisierung]]&lt;br /&gt;
&lt;br /&gt;
== Weiterführende Links ==&lt;br /&gt;
* Weitere Beispiele für Fortgeschrittene, siehe &amp;quot;[[DOIF/uiTable|uiTable mit FHEM-Widgets und Styles]]&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=HourCounter&amp;diff=37165</id>
		<title>HourCounter</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=HourCounter&amp;diff=37165"/>
		<updated>2022-01-28T19:31:15Z</updated>

		<summary type="html">&lt;p&gt;Maista: URL nicht mehr erreichbar&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Modul&lt;br /&gt;
|ModPurpose=HourCounter dient zum Zählen von Ereignissen und zur Erfassung von Betriebs-/Ruhe-Zeiten&lt;br /&gt;
|ModType=h&lt;br /&gt;
&amp;lt;!-- |ModCmdRef=LightScene -- nicht erforderlich, da Modultyp x --&amp;gt;&lt;br /&gt;
|ModForumArea=MAX&lt;br /&gt;
|ModTechName=98_HourCounter.pm&lt;br /&gt;
|ModOwner=John ([http://forum.fhem.de/index.php?action=profile;u=806 Forum] / [[Benutzer Diskussion:John|Wiki]])}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[HourCounter]] ist ein Perl-Modul, das die Anzahl von Ereignissen erfasst. Bei bipolaren Ereignissen wird zusätzlich die Puls- sowie die Pausendauer ermittelt. Im vorliegenden Beispiel wird ein Betriebsstundenzähler mit einem MAX-Fensterkontakt realisiert.&lt;br /&gt;
&lt;br /&gt;
== Features ==&lt;br /&gt;
* Ermittlung von Betriebsstunden, Auslastung, Verbräuchen, Schalthäufigkeiten&lt;br /&gt;
* Ermittlung der Häufigkeit, Puls- Pausendauer pro Tag&lt;br /&gt;
* Ermittlung der Puls-/Pausendauer der letzten Schaltperiode&lt;br /&gt;
* Bereitstellung von Ereignissen zur Fortführung der Kumulation für Tages-, Wochen- und Monatswerte&lt;br /&gt;
* unterstützende Funktionen zur Ablage von Tages-, Wochen- und Monatswerten&lt;br /&gt;
&lt;br /&gt;
== Zielsetzung des WIKI-Artikels ==&lt;br /&gt;
Erläuterung der Funktionalität zur weiterführenden Diskussion im {{Link2Forum|Topic=12216|Message=72596|LinkText=Forum}}.&lt;br /&gt;
&lt;br /&gt;
== Aktuelle Version ==&lt;br /&gt;
Das Modul ist seit dem 24.10.2014 Bestandteil von FHEM.&lt;br /&gt;
&lt;br /&gt;
== Definition ==&lt;br /&gt;
=== Abstrakt ===&lt;br /&gt;
&amp;lt;pre&amp;gt;define &amp;lt;name&amp;gt; HourCounter &amp;lt;regexp_for_ON&amp;gt; [&amp;lt;regexp_for_Off&amp;gt;]&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;regexp_for_ON&amp;gt; ist ein regulärer Ausdruck der das Ereignis beschreibt.&lt;br /&gt;
&lt;br /&gt;
Wenn auch [&amp;lt;regexp_for_Off&amp;gt;] definiert ist, so sprechen wir von einem bipolarem Ereignis, das einen &lt;br /&gt;
EIN- sowie einen AUS-Zustand aufweist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;regexp_for_ON&amp;gt; beschreibt in diesem Fall die positive Flanke,[&amp;lt;regexp_for_Off&amp;gt;] die negative Flanke. Die Struktur des regexp-Ausdruckes ist analog zu jener beim Notify aufgebaut.&lt;br /&gt;
&lt;br /&gt;
===Konkret===&lt;br /&gt;
&amp;lt;pre&amp;gt;define CN.Test HourCounter SHUTTER.JOHN:onoff:.1 SHUTTER.JOHN:onoff:.0&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hier wird der HourCounter CN.TEST definiert.&lt;br /&gt;
Ein MAX-Fensterkontakt mit Namen SHUTTER.JOHN wird als Ereignis-Geber verwendet.&lt;br /&gt;
Das Reading &amp;quot;onoff&amp;quot; wird als Trigger für unserem Zähler genutzt.&lt;br /&gt;
Bei den Fensterkontakten sehen diese Ereignisse wie folgt aus:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
2013-11-15 23:19:12 MAX SHUTTER.JOHN onoff: 1&lt;br /&gt;
....&lt;br /&gt;
2013-11-15 23:19:24 MAX SHUTTER.JOHN onoff: 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soll ein Dummy als Ereignis-Geber verwendet werden, lautet die Definition wie folgt:&lt;br /&gt;
&amp;lt;pre&amp;gt; define CN.Test HourCounter myDummy:1 myDummy:0&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die neue Instanz weist folgende Struktur auf:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Internals:&lt;br /&gt;
   CFGFN      &lt;br /&gt;
   DEF        SHUTTER.JOHN:onoff:.1 SHUTTER.JOHN:onoff:.0&lt;br /&gt;
   NAME       CN.Test&lt;br /&gt;
   NR         738&lt;br /&gt;
   NTFY_ORDER 50-CN.Test&lt;br /&gt;
   STATE      1&lt;br /&gt;
   TYPE       HourCounter&lt;br /&gt;
   Readings:&lt;br /&gt;
     2014-02-04 20:59:22   clearDate       2014-02-04 20:59:22&lt;br /&gt;
     2014-02-04 20:59:57   countsOverall   1&lt;br /&gt;
     2014-02-04 20:59:57   countsPerDay    1&lt;br /&gt;
     2014-02-04 20:59:57   pauseTimeIncrement 35&lt;br /&gt;
     2014-02-04 20:59:57   pauseTimeOverall 35&lt;br /&gt;
     2014-02-04 20:59:57   pauseTimePerDay 35&lt;br /&gt;
     2014-02-04 21:00:01   pulseTimeIncrement 4&lt;br /&gt;
     2014-02-04 21:00:01   pulseTimeOverall 4&lt;br /&gt;
     2014-02-04 21:00:01   pulseTimePerDay 4&lt;br /&gt;
     2014-02-04 20:59:57   state           1&lt;br /&gt;
     2014-02-04 21:00:00   tickHour        1&lt;br /&gt;
     2014-02-04 21:00:01   value           0&lt;br /&gt;
   Helper:&lt;br /&gt;
     OFF_Regexp SHUTTER.JOHN:onoff:.0&lt;br /&gt;
     ON_Regexp  SHUTTER.JOHN:onoff:.1&lt;br /&gt;
     calledByEvent &lt;br /&gt;
     changedTimestamp 2014-02-04 21:00:01&lt;br /&gt;
     forceClear &lt;br /&gt;
     forceDayChange &lt;br /&gt;
     forceHourChange &lt;br /&gt;
     forceMonthChange &lt;br /&gt;
     forceWeekChange &lt;br /&gt;
     isFirstRun &lt;br /&gt;
     sdRoundHourLast 1391544000&lt;br /&gt;
     value      0&lt;br /&gt;
     cmdQueue:&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit nicht zu viele Ereignisse in den Log-Dateien landen, kann man diese sinnvoll einschränken, so daß&lt;br /&gt;
nur Änderungen das Feuern von Events auslösen&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr CN.BRENNER event-on-change-reading .*&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Wenn sich nun jedoch über Stunden und Tage nichts ändert, sieht man in den Charts keine Daten mehr.&lt;br /&gt;
Mit dieser Anweisung wird erreicht, daß alle Readings nach Aktualisierung spätesten nach 1 Stunden einen Event feuern, auch wenn sich der Wert nicht ändert.&lt;br /&gt;
Eine Ausnahme hiervon sollen machen die  tick*-Readings, deren Events sollen immer sofort gefeuert werden, &lt;br /&gt;
wenn sie aktualisiert werden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
attr CN.BRENNER event-min-interval tick.*:0,.*:3600&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Readings ==&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Reading !! class=&amp;quot;unsortable&amp;quot; |  Beschreibung &lt;br /&gt;
|-&lt;br /&gt;
| clearDate || Datum, zu dem alle kumulativen Readings  über set .. clear gelöscht wurden&lt;br /&gt;
|-&lt;br /&gt;
| countsOverall || Absolutzähler für das Auftreten des ON-Ereignisses&lt;br /&gt;
|-&lt;br /&gt;
| countsPerDay  || Tageszähler für das Auftreten des ON-Ereignisses&lt;br /&gt;
|-&lt;br /&gt;
| pauseTimeIncrement || Zeitdauer der Pausen-Phase in Sekunden ; wird zyklisch aktualisiert&lt;br /&gt;
|-&lt;br /&gt;
| pauseTimeEdge || Zeitdauer der letzten komplettierten Pausen-Phase&lt;br /&gt;
|-&lt;br /&gt;
| pauseTimeOverall || Zeitdauer in Sekunden über alle aufgetretenen Pause-Phasen&lt;br /&gt;
|-&lt;br /&gt;
| pauseTimePerDay || Zeitdauer in Sekunden über alle aufgetretenen Pause-Phasen des akt. Tages&lt;br /&gt;
|-&lt;br /&gt;
| pulseTimeIncrement ||  Zeitdauer der Puls-Phase in Sekunden ; wird zyklisch aktualisiert&lt;br /&gt;
|-&lt;br /&gt;
| pulseTimeEdge || Zeitdauer der letzten komplettierten Pulse-Phase&lt;br /&gt;
|-&lt;br /&gt;
| pulseTimeOverall || Zeitdauer in Sekunden über alle aufgetretenen Puls-Phasen&lt;br /&gt;
|-&lt;br /&gt;
| pulseTimePerDay || Zeitdauer in Sekunden über alle aufgetretenen Puls-Phasen des akt. Tages&lt;br /&gt;
|-&lt;br /&gt;
| value || Aktueller Schaltzustand gemäss ON/OFF Ereignis,&amp;lt;br /&amp;gt;&lt;br /&gt;
 mit 1=letztes Ereignis war ON-Ereignis &amp;lt;br /&amp;gt;&lt;br /&gt;
 und 0=letztes Ereignis war OFF-Ereignis&lt;br /&gt;
|-&lt;br /&gt;
| tickUpdated || Event wird gefeuert, wenn die operativen Readings beschrieben worden sind (nicht unbedingt gändert)&lt;br /&gt;
|-&lt;br /&gt;
| tickChanged || Event wird nach Änderung von value gefeuert&lt;br /&gt;
|-&lt;br /&gt;
| tickDay || Event wird nach Tageswechsel gefeuert bevor die Tageszähler resettiert werden&lt;br /&gt;
|-&lt;br /&gt;
| tickHour || Event wird nach Stundenwechsel gefeuert&lt;br /&gt;
|-&lt;br /&gt;
| tickWeek || Event wird nach Wochenwechsel gefeuert&lt;br /&gt;
|-&lt;br /&gt;
| tickMonth || Event wird nach Monatswechsel gefeuert&lt;br /&gt;
|-&lt;br /&gt;
| tickYear || Event wird nach Jahreswechsel gefeuert&lt;br /&gt;
|-&lt;br /&gt;
| forceHourChange || simuliert einen Stundenwechsel&lt;br /&gt;
|-&lt;br /&gt;
| forceDayChange || simuliert einen Tageswechsel&lt;br /&gt;
|-&lt;br /&gt;
| forceWeekChange || simuliert einen Wochenwechsel&lt;br /&gt;
|-&lt;br /&gt;
| forceMonthChange || simuliert einen Monatswechsel&lt;br /&gt;
|-&lt;br /&gt;
| forceYearChange || simuliert einen Jahreswechsel&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Web-Oberfläche ==&lt;br /&gt;
[[Datei:13_11_15_HourCounter_Face.png|HourCounter]]&lt;br /&gt;
&lt;br /&gt;
== Anwendung ==&lt;br /&gt;
Nachfolgende Darstellung zeigt das Einschaltverhalten eines Heizungskessels zusammen mit den &lt;br /&gt;
abgeleiteten Werten.&lt;br /&gt;
&lt;br /&gt;
[[Datei:13_11_15_HourCounter_Chart.png]]&lt;br /&gt;
&lt;br /&gt;
* die Kurve &amp;quot;Brenner EIN&amp;quot; zeigt die Trigger-Signale des ON/OFF Filters, also das Ein-/Ausschalten des Brenners&lt;br /&gt;
* die Kurve &amp;quot;Brenner-Starts&amp;quot; zeigt die über den Tag aufgelaufenen Starts, also chronologisch das Anwachsen von Reading countsPerDay&lt;br /&gt;
* die Kurve &amp;quot;Betriebsstunden&amp;quot; zeigt die aufgelaufene Zeit aus dem Reading pulseTimePerDay umgerechnet zu Stunden&lt;br /&gt;
* die Kurve &amp;quot;Dauer&amp;quot; zeigt die Dauer des letzten Pulses in Sekunden&lt;br /&gt;
* die Kurve Auslastung zeigt das Verhältnis des Readings pulseTimePerDay zur seit Tagesbeginn vergangenen Zeit.&lt;br /&gt;
&lt;br /&gt;
=== Chart der Aktualwerte ===&lt;br /&gt;
Wir benötigen hierzu ein File-Archiv für die aufgelaufenen Daten.&lt;br /&gt;
&amp;lt;pre&amp;gt;define CN.Test.File FileLog ./log/CN.Test-%Y.log (CN\.Test:.*)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Man erhält nach den ersten Ereignissen Einträge in folgender Form:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
2013-11-16_12:45:40 CN.Test value: 1&lt;br /&gt;
2013-11-16_12:45:40 CN.Test 1&lt;br /&gt;
2013-11-16_12:46:21 CN.Test pulseTimeIncrement: 41    &lt;br /&gt;
2013-11-16_12:46:21 CN.Test pulseTimePerDay: 41&lt;br /&gt;
2013-11-16_12:46:21 CN.Test pulseTimeOverall: 41&lt;br /&gt;
2013-11-16_12:46:21 CN.Test value: 0&lt;br /&gt;
2013-11-16_12:50:38 CN.Test countsPerDay: 2&lt;br /&gt;
2013-11-16_12:50:38 CN.Test countsOverall: 2&lt;br /&gt;
2013-11-16_12:50:38 CN.Test pauseTimeIncrement: 257&lt;br /&gt;
2013-11-16_12:50:38 CN.Test pauseTimePerDay: 756&lt;br /&gt;
2013-11-16_12:50:38 CN.Test pauseTimeOverall: 756&lt;br /&gt;
2013-11-16_12:50:38 CN.Test value: 1&lt;br /&gt;
2013-11-16_12:50:38 CN.Test 2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun kann man den Chart definieren:&lt;br /&gt;
[[Datei:13_11_16_HourCounter_ChartBuild_01.png]]&lt;br /&gt;
&lt;br /&gt;
Für die Kurve &amp;quot;Brenner EIN&amp;quot; verwenden wir CN.Test.value. Damit diese als unterste Kurve dargestellt wird transformieren wir den Wert 1 auf -2 und alle anderen (also die 0) auf -21 mit folgender Funktion:&lt;br /&gt;
&amp;lt;pre&amp;gt;$fld[3]=~&amp;quot;1&amp;quot;?-2:-19&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die &amp;quot;Brenner Starts&amp;quot; können wir direkt von countsPerDay ableiten.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Für die &amp;quot;Betriebsstunden&amp;quot; verwenden wir pulseTimePerDay. Da diese in Sekunden vorliegen teilen wir den Wert durch 3600, um Stunden zu erhalten.&lt;br /&gt;
&amp;lt;pre&amp;gt;$fld[3]/=3600&amp;lt;/pre&amp;gt;&lt;br /&gt;
Als letzten versorgen wir noch die Kurve &amp;quot;Dauer&amp;quot; mit pulseTimeIncrement. Da wir diese in Minuten haben wollen ist ebenfalls eine Umformung nötig.&lt;br /&gt;
&amp;lt;pre&amp;gt;$fld[3]/=60&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Somit sind die Basis-Kurven angelegt.&lt;br /&gt;
&lt;br /&gt;
=== Erweiterungen ===&lt;br /&gt;
Es wurden im Forum viele Wünsche formuliert, weitere Funktionalitäten für den HourCounter einzuführen.&lt;br /&gt;
&lt;br /&gt;
* Aggregation über bestimmte oder ganz freie Zeiträume&lt;br /&gt;
* komplexe Berechnungen, die zum Verbrauch führen&lt;br /&gt;
* Zuordnung von Verbräuchen zu unterschiedlichen Countern nach bestimmten Bedingungen&lt;br /&gt;
&lt;br /&gt;
Vor allem die Aggregation erfasster Werte in Stunden-, Tages-, Wochen- und Monatswerten ist eine sinnvolle&lt;br /&gt;
Erweiterung bei der Verbrauchserfassung.&lt;br /&gt;
&lt;br /&gt;
HourCounter bietet Schnittstellen an, die es ermöglichen, das Modul selbst mit neuen Eigenschaften zu erweitern.&lt;br /&gt;
&lt;br /&gt;
Die Referenz-Implementierung in 99_UtilsHourCounter.pm zeigt, wie dies skript-technisch zu realisieren ist.&lt;br /&gt;
&lt;br /&gt;
==== Installation ====&lt;br /&gt;
Die jeweils aktuelle Version von 99_UtilsHourCounter kann über diesen &lt;br /&gt;
[https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/99_UtilsHourCounter.pm Link] bezogen werden.&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Die Datei ist in da Unterverzeichnis FHEM vom FHEM-Homverzeichnis zu kopieren.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
z.B. bei Raspberry Pi: /opt/fhem/FHEM&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Nach dem Kopieren und einen Neustart von FHEM kann man überprüfen, ob FHEM diese Datei findet.&lt;br /&gt;
Wenn man das Menü &amp;quot;Edit Files &amp;quot; anwählt, wird auch 99_UtilsHourCounter angezeigt.&lt;br /&gt;
&lt;br /&gt;
==== Readings ====&lt;br /&gt;
99_UtilsHourCounter aus dem contrib-Verzeichnis der FHEM-Installation erweitert den HourCounter um folgende Funktionen:&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Reading !! class=&amp;quot;unsortable&amp;quot; |  Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
| appCountsPerHour || Stundenzähler, wird bei Stundenwechsel aktualisiert&lt;br /&gt;
|-&lt;br /&gt;
| appCountsPerHourTemp || Arbeitszähler zu appCountsPerHour&lt;br /&gt;
|-&lt;br /&gt;
| appCountsPerDay || Tageszähler, wird bei Tageswechsel aktualisiert (Arbeitszähler ist countsPerDay)&lt;br /&gt;
|-&lt;br /&gt;
| appCountsPerWeek || Wochenzähler, wird bei Wochenwechsel aktualisiert&lt;br /&gt;
|-&lt;br /&gt;
| appCountsPerWeekTemp || Arbeitszähler zu appCountsPerWeek&lt;br /&gt;
|-&lt;br /&gt;
| appCountsPerMonth || Monatszähler, wird bei Monatswechsel aktualisiert&lt;br /&gt;
|-&lt;br /&gt;
| appCountsPerMonthTemp || Arbeitszähler zu appCountsPerMonth&lt;br /&gt;
|-&lt;br /&gt;
| appCountsPerYear || Jahreszähler, wird bei Jahreswechsel aktualisiert&lt;br /&gt;
|-&lt;br /&gt;
| appCountsPerYearTemp || Arbeitszähler zu appCountsPerYear&lt;br /&gt;
|-&lt;br /&gt;
| appOpHoursPerDay || Betriebsstunden des Tages&lt;br /&gt;
|-&lt;br /&gt;
| appOpHoursPerDayTemp || Arbeitszähler zu appOpHoursPerDay&lt;br /&gt;
|-&lt;br /&gt;
| appOpHoursPerWeek || Betriebsstunden der Woche&lt;br /&gt;
|-&lt;br /&gt;
| appOpHoursPerWeekTemp || Arbeitszähler zu appOpHoursPerWeek&lt;br /&gt;
|-&lt;br /&gt;
| appOpHoursPerMonth || Betriebsstunden des Monats&lt;br /&gt;
|-&lt;br /&gt;
| appOpHoursPerMonthTemp || Arbeitszähler appOpHoursPerMonth&lt;br /&gt;
|-&lt;br /&gt;
| appOpHoursPerYear || Betriebsstunden des Jahres&lt;br /&gt;
|-&lt;br /&gt;
| appOpHoursPerYearTemp || Arbeitszähler appOpHoursPerYear&lt;br /&gt;
|-&lt;br /&gt;
| appUtilization || Auslastung = pulseTimePerDay /(vergangene Sekunden seit Tagesbeginn) * 100&lt;br /&gt;
|-&lt;br /&gt;
| appUtilizationTemp || Arbeitsvariable zu appUtilization&lt;br /&gt;
|}&lt;br /&gt;
Beginn der Woche ist jeweils der Sonntag.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit folgender Anweisung aktivieren wir die Erweiterungen: &lt;br /&gt;
:&amp;lt;code&amp;gt;define CN.EVENT notify CN\..*:tick.* { appHCNotify(&amp;quot;$NAME&amp;quot;,&amp;quot;$EVTPART0&amp;quot;,&amp;quot;$EVTPART1&amp;quot;);;}&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Spätestens nach einer steigenden und einer fallenden Flanke sind die zuvor genannten app*-Readings zu sehen.&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=Die gezeigten define-Anweisungen müssen jeweils in einer Zeile stehen (keine Zeilenumbrüche!).}}&lt;br /&gt;
&lt;br /&gt;
Die neuen Readings werden automatisch  in den &amp;quot;Setter&amp;quot; der Web-Oberflächen aufgenommen. Dies gilt für alle Readings, die mit &amp;quot;app&amp;quot; beginnen.&lt;br /&gt;
&lt;br /&gt;
Somit können die neuen Readings beliebig manipuliert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== Für Anfänger die noch keine Erfahrungen mit Regular Expressions haben:=====&lt;br /&gt;
Benennt eure Hourcounter nach dem Muster CN.&amp;lt;euer Wunschname&amp;gt;. Dann wird der notify immer funktionieren.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel: statt &amp;quot;PelletsCounter&amp;quot; wählt den Namen &amp;quot;CN.PelletsCounter&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Archiv für Tages-/Wochen-/Monats-/Jahreswerte anlegen ====&lt;br /&gt;
Nun wollen wir die aggregierten Werte in eine eigene Datei speichern. Dies gelingt mit &lt;br /&gt;
:&amp;lt;code&amp;gt;define CN.Test.FileDay FileLog ./log/CN.Test-Day-%Y.log CN.Test:app\w*(Utilization|PerHour|PerDay|PerWeek|PerMonth|PerYear)(?!Temp).* &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Im Klartext:&lt;br /&gt;
* verwende alle Werte des Counters CN.Test, deren Reading mit &amp;quot;app&amp;quot; beginnt&lt;br /&gt;
* und die einen der Terme appUtilization|PerHour|PerDay|PerWeek|PerMonth|PerYear beinhalten&lt;br /&gt;
* und die danach nicht dem Term &amp;quot;Temp&amp;quot; beinhalten&lt;br /&gt;
&lt;br /&gt;
== Fragen und Antworten ==&lt;br /&gt;
==== Betriebsstundenzähler über Leistungsmessung ableiten ====&lt;br /&gt;
&#039;&#039;&#039;Frage:&#039;&#039;&#039;&lt;br /&gt;
Ich würde gerne zählen, wenn ich mehr Strom als Standy verbrauche (also mehr als 2Watt)&lt;br /&gt;
und keine Betriebsstunden zählen, wenn der Verbrauch unter 2 Watt ist. Ist das möglich?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Beispiel für die Events&amp;lt;/u&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
013-11-18_19:40:32 XXX power: 1.9&lt;br /&gt;
2013-11-18_19:40:32 XXX consumption: 2&lt;br /&gt;
2013-11-18_19:40:32 XXX consumptionTotal: 2&lt;br /&gt;
2013-11-18_19:40:36 XXX power: 27&lt;br /&gt;
2013-11-18_19:40:36 XXX consumption: 2&lt;br /&gt;
2013-11-18_19:40:36 XXX consumptionTotal: 2&lt;br /&gt;
2013-11-18_19:40:42 XXX power: 34.6&lt;br /&gt;
2013-11-18_19:40:42 XXX consumption: 2 &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Antwort&#039;&#039;&#039;&lt;br /&gt;
Die hier vorgestellte Lösung überprüft ob der Wert des Events power eine oder zwei Ziffern vor dem Komma hat.&lt;br /&gt;
Deshalb wir hier erst gezählt, wenn die Schwelle von 10Watt überschritten wird. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define CN.Test HourCounter XXX:power:\s[0-9]{2,}(\.[0-9]{1,3})*$  XXX:power:\s[0-9]{1}(\.[0-9]{1,3})*$&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Erläuterung zu &amp;lt;regexp_for_ON&amp;gt; = XXX:power:\s[0-9]{2,}(\.[0-9]{1,3})*$&lt;br /&gt;
* &amp;quot;XXX&amp;quot;  bezeichnet das Device, der Term danach ist der regexp-Filte für das On-Ereignis&lt;br /&gt;
* &amp;quot;power:&amp;quot; das Ereignis muss mit diesem Term beginnen&lt;br /&gt;
* &amp;quot;\s&amp;quot; es muss ein Leerzeichen folgen&lt;br /&gt;
* &amp;quot;[0-9]{2,}&amp;quot; es müssen mindestens 2 Ziffern folgen&lt;br /&gt;
* &amp;quot;(\.[0-9]{1,3})*&amp;quot; wenn ein Punkt folgt, dann müssen auf diesen mindestens 1..3 Ziffern folgen&lt;br /&gt;
* &amp;quot;$&amp;quot; danach darf kein weiteres Zeichen mehr folgen&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Antwort Möglichkeit 2&#039;&#039;&#039;&lt;br /&gt;
In dieser Lösung bekommt das entsprechende Device was mit HourCounter überwacht werden soll ein userReadings &amp;quot;onoff&amp;quot;. Dieses Reading wird dann zum Schalten von Hour Counter verwendet:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define GPIO4_DS18B20_Waermepumpe_Vorlauf GPIO4 28-000005956079&lt;br /&gt;
attr GPIO4_DS18B20_Waermepumpe_Vorlauf alias Wärmepumpe Vorlauf&lt;br /&gt;
attr GPIO4_DS18B20_Waermepumpe_Vorlauf model DS18B20&lt;br /&gt;
attr GPIO4_DS18B20_Waermepumpe_Vorlauf room GPIO4&lt;br /&gt;
attr GPIO4_DS18B20_Waermepumpe_Vorlauf userReadings onoff {(ReadingsVal(&amp;quot;GPIO4_DS18B20_Waermepumpe_Vorlauf&amp;quot;,&amp;quot;temperature&amp;quot;,0) &amp;gt;28)?1:0;;}&lt;br /&gt;
&lt;br /&gt;
define Waermepumpe_HourCounter HourCounter GPIO4_DS18B20_Waermepumpe_Vorlauf:onoff:.1  GPIO4_DS18B20_Waermepumpe_Vorlauf:onoff:.0&lt;br /&gt;
attr Waermepumpe_HourCounter room 2_Fussbodenheizung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Erläuterungen zu dem Code: &amp;quot;{(ReadingsVal(&amp;quot;GPIO4_DS18B20_Waermepumpe_Vorlauf&amp;quot;,&amp;quot;temperature&amp;quot;,0) &amp;gt;28)?1:0;;}&amp;quot;&lt;br /&gt;
* &amp;quot;(ReadingsVal(&amp;quot;GPIO4_DS18B20_Waermepumpe_Vorlauf&amp;quot;,&amp;quot;temperature&amp;quot;,0) &amp;gt;28)&amp;quot; Diese Bedingung für das userReadings onoff prüft bei jedem Event, ob der Wert von temperature größer als 28 ist. &lt;br /&gt;
* &amp;quot;?1:0&amp;quot; Ist dies der Fall wird das userReading onoff auf 1 gesetzt andernfalls auf 0.&lt;br /&gt;
Auf Basis deses UserReadings wird dann der HourCounter definiert:&lt;br /&gt;
* &amp;quot;GPIO4_DS18B20_Waermepumpe_Vorlauf:onoff:.1&amp;quot; Einschaltbedingung für HourCounter&lt;br /&gt;
* &amp;quot;GPIO4_DS18B20_Waermepumpe_Vorlauf:onoff:.0&amp;quot; Abschaltbedingung für Hour Counter&lt;br /&gt;
&lt;br /&gt;
==== Welche Anwendungsfälle sind denkbar ? ====&lt;br /&gt;
{{Link2Forum|Topic=12216|Message=175163|LinkText=Aus dem Forum}}&lt;br /&gt;
* Betriebsstundenzähler für meine &amp;quot;Fliegenkiller-Steckdose&amp;quot;&lt;br /&gt;
* Nutzungsdauer beschränken für TV,Internet oder Spielkonsolen für entnervte Eltern&lt;br /&gt;
* Nutzungsdauer ermitteln zur Energieeinsparung (Klimageräte, Ventilatoren, Dunstabzugshauben etc.)&lt;br /&gt;
* Lüftungsverhalten ermitteln (wie lange Fenster pro Tag geöffnet)&lt;br /&gt;
&lt;br /&gt;
{{Link2Forum|Topic=12216|Message=195358|LinkText=Brenner Starts/Verbrauch + akkumulierte Werte}}&lt;br /&gt;
&lt;br /&gt;
{{Link2Forum|Topic=12216|Message=196358|LinkText=Ölverbrauch+Solar-Ladung}}&lt;br /&gt;
&lt;br /&gt;
[http://voizchat.de/gaszaehler-verbrauch-erfassen-mit-fhem-und-raspberry-gpio/ Gaszähler mit HourCounter realisieren] (URL tot)&lt;br /&gt;
&lt;br /&gt;
==== Seltene Schaltvorgänge ====&lt;br /&gt;
Die Schaltvorgänge sind über den Tag sehr wenige. Die Aktualisierung erfolgt immer erst&lt;br /&gt;
bei der negativen Flanke. Wie kann man eine häufigere Aktualisierung erreichen ?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Antwort&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ab Version 1.0.0.6 ist wurde das Attribut &amp;quot;interval&amp;quot; eingeführt; es ist auf 60 Minuten voreingestellt und kann von 5..60 im 5 Minuten-Raster festgelegt werden.&lt;br /&gt;
Es bestimmt, nach welcher Zeit Puls-/Pausendauer aktualisiert werden sollen, unabhängig vom Auftreten einer Schaltflanke.&lt;br /&gt;
&lt;br /&gt;
==== Korrekte Darstellung der akkumulierten Daten im Chart ====&lt;br /&gt;
&#039;&#039;&#039;Frage&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;appCountsPerDay: 4&amp;quot; bezieht sich auf die Counts des Tages 2014-06-16, trägt aber selbst den Zeitstempel 2014-06-17 und wird demnach in einem Chart auch über den Tag  &amp;quot; 2014-06-17&amp;quot; dargestellt.&lt;br /&gt;
Das Problem betrifft alle akkumulierten Daten des HourCounters.&lt;br /&gt;
Wie erreicht man im Chart die korrekte Darstellung ?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Antwort&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Das Thema wurde {{Link2Forum|Topic=12216|Message=239929|LinkText=hier}} disktuiert.&lt;br /&gt;
Eine Lösung findet man mit [[LogProxy]].&lt;br /&gt;
Damit läßt sich ein negativer Offset für die X-Achse definieren, so daß die Daten wieder korrekt dargestellt werden.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:MAX]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:Heizungssteuerung]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Synology_Diskstation&amp;diff=36167</id>
		<title>Synology Diskstation</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Synology_Diskstation&amp;diff=36167"/>
		<updated>2021-11-01T14:58:40Z</updated>

		<summary type="html">&lt;p&gt;Maista: Fhem &amp;gt; FHEM&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== FHEM Installation auf der Synology Diskstation (ab DSM 5)==&lt;br /&gt;
&lt;br /&gt;
FHEM auf einer Synology Diskstation (DS) zu installieren ist grundsätzlich nicht schwierig. Wichtig ist zunächst eine aktuelle DSM - also Systemupdates auf der DS installieren.&lt;br /&gt;
&lt;br /&gt;
* Zunächst installiert ihr Euch über das Paket-Zentrum der DS das Programm &amp;quot;Perl&amp;quot;. &lt;br /&gt;
* Dann besorgt ihr Euch von Martin Fischer ein kompiliertes FHEM [https://www.fischer-net.de/hausautomation/downloads/category/11-fhem.html SPK]. Mehr Infos s. {{Link2Forum|Topic=51265}}&lt;br /&gt;
* Dann wieder den Paket-Zentrum der DS aufrufen und &amp;quot;Manuelle Installation&amp;quot; -&amp;gt; entsprechende Datei auswählen -&amp;gt; weiter. Wenn es Mecker gibt wegen Signierung o.ä., dann Paket-Zentrum -&amp;gt; Einstellungen -&amp;gt; Vertrauensebene auf &amp;quot;Jeder Herausgeber&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Danach ist FHEM installiert und ihr könnt es über das Paket-Zentrum starten. Dann einfach FHEM aufrufen und als erstes mal ein Update durchführen. &lt;br /&gt;
Nach dem Update die Datei 99_update.pm löschen, siehe {{Link2Forum|Topic=36249|Message=285521|LinkText=hier}}&lt;br /&gt;
&lt;br /&gt;
Um einen CUL damit zu betreiben oder HUEs anzusteuern müssen noch weitere Schritte unternommen werden. (siehe weiter unten)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Hinweis:&amp;lt;/i&amp;gt; Falls man eine neuere Version von Perl benötigt bzw. Probleme auftreten, dann kann auf x86_64-Architekturen (s. [http://www.synology-wiki.de/index.php/Welchen_Prozessortyp_besitzt_mein_System%3F]) auch ActivePerl eingesetzt werden. Dazu muss man nur das Startskript von FHEM anpassen. Dann kann man beide Versionen auch parallel betreiben. Nur bei CPAN/PPM darauf achten, in welchem Verzeichnis man das aufruft.&lt;br /&gt;
&lt;br /&gt;
Hier noch Links zu Wiki-Einträgen für ältere DSM-Versionen / Modelle:&lt;br /&gt;
[[FHEM auf dem Synology DS408]]&lt;br /&gt;
&lt;br /&gt;
== CUL zum laufen bringen | IPKG installieren ==&lt;br /&gt;
A.) Zunächst braucht ihr die USB-Treiber: http://forum.synology.com/enu/viewtopic.php?f=155&amp;amp;t=82843&amp;amp;hilit=usbserial - diese einfach über das Paket-Zentrum installieren. Die Zusatzkonfigurationen, die vom Wizard nach der Installation gefragt werden, müssen nicht ausgewählt werden.&lt;br /&gt;
&lt;br /&gt;
B.) Dann braucht ihr das IPKG, damit ihr verschiedene Programme nachladen könnt, die ihr für den Betrieb des CUL benötigt:&lt;br /&gt;
1. Prozessor (CPU) Architektur heraussuchen - http://forum.synology.com/wiki/index.php/What_kind_of_CPU_does_my_NAS_have&lt;br /&gt;
2. Der Prozessor (CPU) Architektur entsprechendes Shell-Script herunterladen und in einem beliebigen Ordner auf der DiskStation speichern - http://forum.synology.com/wiki/index.php/Overview_on_modifying_the_Synology_Server,_bootstrap,_ipkg_etc#Bootstrap&lt;br /&gt;
Wenn ihr den Prozessor Marvel Armada XP oder Marvel Armada 370 habt (z.B. DS 214+), dann schaut hier: https://gist.github.com/marlun78/9349792&lt;br /&gt;
3. Dieses How-to durch arbeiten - http://forum.synology.com/wiki/index.php/How_to_Install_Bootstrap (für den Armada nicht - da steht alles im o.g. Link)&lt;br /&gt;
4. DiskStation neustarten&lt;br /&gt;
&lt;br /&gt;
C) Jetzt braucht ihr die SerialPort Modul.&lt;br /&gt;
Das kann funktionieren mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;quot;ipkg install gcc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/usr/local/perl/bin/perl -MCPAN -e shell&amp;quot;) / je nachdem wo Eure perl Installation liegt - bei mir war es &amp;quot;/usr/bin/perl -MCPAN -e shell&amp;quot; &lt;br /&gt;
&lt;br /&gt;
&amp;quot;cpan install Device::SerialPort&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hat es bei mir nicht - ich habe es so geschafft:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;quot;ipkg install perl-device-serialport&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;cp /opt/lib/perl5/site_perl/5.10.0/arm-linux/Device/SerialPort.pm /volume1/@appstore/Perl/lib/perl5/site_perl/Device/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;cp /opt/lib/perl5/site_perl/5.10.0/arm-linux/auto/Device/SerialPort/SerialPort.bs /volume1/@appstore/Perl/lib/perl5/site_perl/auto/Device/SerialPort/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;cp /opt/lib/perl5/site_perl/5.10.0/arm-linux/auto/Device/SerialPort/SerialPort.so /volume1/@appstore/Perl/lib/perl5/site_perl/auto/Device/SerialPort/&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keine der beiden Varianten funktioniert für DS213+ (Stand: Juni 2015). Alternative für DS213+ siehe [[Synology Diskstation DS213+|hier]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
D) ganz wichtig - sonst schmiert Euch der CUL immer wieder ab - synousbmdemd deaktivieren - das habe ich wie folgt gemacht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;mv /usr/syno/sbin/synousbmodemd /usr/syno/sbin/synousbmodemd_bkp&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei einem DSM update wird dieser Dienst vermutlich wieder installiert - daher nach einem Update same procedure as every year.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;Security Advisor&amp;quot; erkennt diese Änderung und glaubt, dass sich eine Malware auf dem NAS breitgemacht hätte. Man erhält deswegen eine entsprechende Warnung.&lt;br /&gt;
&lt;br /&gt;
== Wichtig: Logfile auf USB auslagern ==&lt;br /&gt;
Damit die DS auch ab und zu mal die Platten zum schlafen schicken kann, solltet ihr die Logfiles auf ein USB-Laufwerk auslagern. Dazu einfach eines an die DS anschließen und im File-Explorer nachschauen, wie das Laufwerk benannt wurde (z.B. volumeUSB1). Dann FHEM runterfahren (&amp;quot;shutdown&amp;quot;), anschließend als root über z.B. putty mit der DS verbinden, das Log-Verzeichnis auf den Stick verschieben und einen Link anlegen - z.B. so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;mv /usr/local/FHEM/var/log /volumeUSB1/usbshare/fhem/log&lt;br /&gt;
&lt;br /&gt;
ln -s /volumeUSB1/usbshare/fhem/log /usr/local/FHEM/var/log&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dann Fhem wieder starten und es sollte klappen.&lt;br /&gt;
&lt;br /&gt;
== Inhalt von Fhem-Verzeichnissen aus Windows direkt bearbeiten ==&lt;br /&gt;
Hier gibt es mehrere Möglichkeiten. Entweder ihr verbindet Euch über WinSCP mit der DS. Oder aber ihr verschiebt und verknüpft noch weitere Teile der FHEM Installation auf den Stick (siehe Logfile auf USB auslagern). Hier wäre ich allerdings vorsichtig, da kann FHEM zickig werden. Ich persönlich habe mir die fhem.cfg auf diese Weise noch auf den Stick geschoben - also das /usr/local/FHEM/etc Verzeichnis analog obiger Beschreibung zum Logfile. Darüber hinaus könnt ihr auch einfach Dateien auf Eurem Stick ablegen und im entsprechenden FHEM-Verzeichnis einen Link dazu erstellen - so habe ich das z.B. mit meinen pm-Files gemacht - z.B.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ln -s /volumeUSB1/usbshare/fhem/99_myUtils.pm /usr/local/FHEM/share/fhem/FHEM/99_myUtils.pm&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== HUE auf der Synology Diskstation ==&lt;br /&gt;
Da auf der DS standardmäßig kein JSON installiert ist, muss dies nachinstalliert werden (Danke an Patlinger für die Anleitung). Wichtig - ihr braucht IPKG (siehe CUL zum Laufen bringen):&lt;br /&gt;
&lt;br /&gt;
1. Per SSH verbinden (Befehl &amp;quot;ssh &amp;lt;ip-adresse&amp;gt; -l root&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
2. Superuser aktivieren (Befehl &amp;quot;su&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
3. &amp;quot;make&amp;quot; installieren (Befehl &amp;quot;ipkg install make&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
4. PERL und CPAN starten (Befehl &amp;quot;/usr/local/perl/bin/perl -MCPAN -e shell&amp;quot;) / je nachdem wo Eure perl Installation liegt - bei mir war es &amp;quot;/usr/bin/perl -MCPAN -e shell&amp;quot;&lt;br /&gt;
&lt;br /&gt;
5. CPAN updaten (Befehl &amp;quot;install CPAN&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
6. JSON installieren (Befehl &amp;quot;install JSON&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
7. Per telnet verbinden (Befehl &amp;quot;telnet &amp;lt;ip-adresse&amp;gt; &amp;lt;port (7072)&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
8. FHEM Update durchführen (Befehl &amp;quot;update&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
9. FHEM Neustart (Befehl &amp;quot;shutdown restart&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
10. Hue Bridge hinzufügen (Befehl &amp;quot;define &amp;lt;Name-für-die-Bridge&amp;gt; HUEBridge &amp;lt;ip-adresse-der-Hue-Bridge&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
11. Taste an der Hue Bridge drücken um das &amp;quot;Pairing&amp;quot; zu bestätigen.&lt;br /&gt;
&lt;br /&gt;
12. GANZ WICHTIG - Wenn&#039;s jetzt einmal läuft, dann nicht vergessen die Konfiguration zu speichern! (Befehl &amp;quot;save&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
== Net::Telnet installieren ==&lt;br /&gt;
Net::Telnet benötigt ihr beispielsweises für das geniale Modul FRITZBOX, dass Euch viele Möglichkeiten eröffnet, wenn ihr einen solchen Router besitzt.&lt;br /&gt;
&lt;br /&gt;
Los gehts wie üblich mit &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;quot;/usr/bin/perl -MCPAN -e shell&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
Der Pfad zu perl kann bei Euch auch anders lauten, siehe oben. Dann seid ihr fast fertig, nur noch folgendes eingeben - und fertig:&lt;br /&gt;
&amp;lt;code&amp;gt;install Net::Telnet&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== JeeLink ==&lt;br /&gt;
&lt;br /&gt;
Für den JeeLink werden zwei Kernelmodule gebraucht, die seit DSM 5.2 dabei sind und nicht mehr separat installiert werden müssen. Jedoch müssen sie nach jedem Update wieder neu aktiviert werden (kann auch bei laufendem Betrieb von FHEM passieren):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /lib/modules&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;insmod usbserial.ko&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;insmod ftdi_sio.ko&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ansonsten wird wie oben beschrieben das &amp;lt;code&amp;gt;Device::SerialPort&amp;lt;/code&amp;gt;-Modul benötigt.&lt;br /&gt;
&lt;br /&gt;
Getestet auf DSM415+&lt;br /&gt;
&lt;br /&gt;
== Automatischer Neustart == &lt;br /&gt;
&lt;br /&gt;
Script anlegen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
cnt=$(ps -A -f | grep &amp;quot;fhem\.pl&amp;quot; | grep -v grep | wc -l)&lt;br /&gt;
if [ &amp;quot;$cnt&amp;quot; -eq &amp;quot;0&amp;quot; ] ; then&lt;br /&gt;
   /var/packages/FHEM/scripts/start-stop-status restart&lt;br /&gt;
else&lt;br /&gt;
  echo &amp;quot;FHEM still running.&amp;quot;;&lt;br /&gt;
  return 1;&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dann kann man entweder über cron das Skript regelmäßíg (z.B. alle 15min) oder man nutzt hierfür die in DSM eingebaute Aufgabenverwaltung (einfach vollständigen Pfad zum Skript eingeben). Letzteres ist für den Überblick auf praktischer.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:Synology]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=At&amp;diff=35973</id>
		<title>At</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=At&amp;diff=35973"/>
		<updated>2021-08-24T17:03:31Z</updated>

		<summary type="html">&lt;p&gt;Maista: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:at}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Setzt einen Fhem-Befehl zu einem späteren Zeitpunkt ab.&lt;br /&gt;
|ModType=h&lt;br /&gt;
&amp;lt;!-- |ModCategory= (noch?) nicht verwendet --&amp;gt;&lt;br /&gt;
|ModCmdRef=at&lt;br /&gt;
|ModTechName=90_at.pm&lt;br /&gt;
|ModOwner=rudolfkoenig / [http://forum.fhem.de/index.php?action=profile;u=8 rudolfkoenig]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[at]] ist ein Erweiterungsmodul, mit dessen Hilfe FHEM-Befehle/-Aktionen zu einem späteren Zeitpunkt ausgeführt werden können. Es läßt sich sowohl einmalige Ausführung, als auch regelmäßige Wiederholung erzielen, Zeitangaben können relativ oder absolut erfolgen.&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen ==&lt;br /&gt;
&amp;lt;!-- AUSKOMMENTIERT wegen derzeitiger Funktionsproblemen iZm codemirror {{Randnotiz|RNTyp=[g|Info|RNText=FHEM enthält für at eine eingebaute Perl-Syntax-Prüfung. Diese ist nach [http://fhem.de/commandref.html#perlSyntaxCheck Aktivierung] aber nur aktiv, wenn die [[Konfiguration]] -wie empfohlen- nicht direkt bearbeitet wird. ({{Link2Forum|Topic=51744}}) }} --&amp;gt;&lt;br /&gt;
Keine.&lt;br /&gt;
&lt;br /&gt;
== Anwendung ==&lt;br /&gt;
=== Define ===&lt;br /&gt;
&amp;lt;code&amp;gt;define &amp;lt;name&amp;gt; at &amp;lt;timespec|datespec&amp;gt; &amp;lt;command&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
=== Besonderheit ===&lt;br /&gt;
*timespec - &#039;&#039;&#039;nur Zeit&#039;&#039;&#039; im Format HH:MM:SS &#039;&#039;&#039;kann eine&#039;&#039;&#039; Perlfunktion sein. &lt;br /&gt;
*datespec - &#039;&#039;&#039;Datum und Zeit&#039;&#039;&#039; ISO 8601 oder &amp;quot;number of sec since 1970&amp;quot; &#039;&#039;&#039;darf keine&#039;&#039;&#039; Perlfunktion sein.&lt;br /&gt;
Siehe {{Link2Forum|Topic=91625|Message=168475}} &lt;br /&gt;
&lt;br /&gt;
=== Beispiele ===&lt;br /&gt;
*&amp;lt;code&amp;gt;define MeineAktion at 02:02:00 set lamp on&amp;lt;/code&amp;gt; →              das nächste Mal um zwei Minuten nach 2 Uhr &amp;quot;lamp&amp;quot; einschalten&lt;br /&gt;
*&amp;lt;code&amp;gt;define MeineAktion at *02:02:00 set lamp on&amp;lt;/code&amp;gt; →             jeden Tag um zwei Minuten nach 2 Uhr &amp;quot;lamp&amp;quot; einschalten&lt;br /&gt;
*&amp;lt;code&amp;gt;define MeineAktion at {ReadingsVal(&amp;quot;Dummy&amp;quot;,&amp;quot;Zeit&amp;quot;,&amp;quot;&amp;quot;)} set lamp on&amp;lt;/code&amp;gt; →              das nächste Mal um (Perlfunktion liest Zeit aus dem Dummy) &amp;quot;lamp&amp;quot; einschalten&lt;br /&gt;
*&amp;lt;code&amp;gt;define MeineAktion at 2016-01-25T02:02:00 set lamp on&amp;lt;/code&amp;gt; →              das nächste Mal am 25.01.2016 um zwei Minuten nach 2 Uhr &amp;quot;lamp&amp;quot; einschalten (ISO 8601)&lt;br /&gt;
*&amp;lt;code&amp;gt;define MeineAktion at 1453683720 set lamp on&amp;lt;/code&amp;gt; →              das nächste Mal am 25.01.2016 um zwei Minuten nach 2 Uhr &amp;quot;lamp&amp;quot; einschalten (number of sec since 1970)&lt;br /&gt;
*&amp;lt;code&amp;gt;define MeineAktion at +02:02:00 set lamp on&amp;lt;/code&amp;gt;    →         in zwei Stunden und 2 Minuten &amp;quot;lamp&amp;quot; einschalten&lt;br /&gt;
*&amp;lt;code&amp;gt;define MeineAktion at +*02:02:00 set lamp on&amp;lt;/code&amp;gt;   →        alle zwei Stunden und 2 Minuten &amp;quot;lamp&amp;quot; einschalten&lt;br /&gt;
Um datespec auch variabel mit setzen zu können gibt es einen Workaround: Perlebene, Perlfunktion und Übergabe in Variable. &lt;br /&gt;
&lt;br /&gt;
Beispiele für &amp;quot;number of seconds since 1970&amp;quot;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
{my $time=time_str2num(&amp;quot;2019-09-14 23:00:00&amp;quot;);;fhem(&amp;quot;define MeineAktion at $time set lamp on&amp;quot;)}&lt;br /&gt;
{my $time=1568494800;;fhem(&amp;quot;define MeineAktion at $time set lamp on&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Beispiel im ISO 8601 Format&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;{my $time=&amp;quot;2019-09-14T23:00:00&amp;quot;;;fhem(&amp;quot;define MeineAktion at $time set lamp on&amp;quot;)}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mehrere Aktionen ausführen ===&lt;br /&gt;
Die Verwendung der Semikolon erfordert immer besondere Aufmerksamkeit!&lt;br /&gt;
*&amp;lt;code&amp;gt;set lampe1 on ; set lampe2 on &amp;lt;/code&amp;gt;   →        Schaltet sofort beide Lampen ein ( ein bisschen OT, weil kein at)&lt;br /&gt;
*&amp;lt;code&amp;gt;define morgens at *7:00:00 set lampe1 on ; set lampe2 on&amp;lt;/code&amp;gt;   →     schaltet lampe 1 immer um 7 an, aber lampe2 sofort. Der erste Befehl landet in der config (im at) der zweite Befehl wird genau wie der define Befehl einfach sofort ausgeführt.  &lt;br /&gt;
*&amp;lt;code&amp;gt;define morgens at *7:00:00 set lampe1 on ;; set lampe2 on&amp;lt;/code&amp;gt;   →     schaltet BEIDE Lampen immer um 7 an. Beide Befehle landen in der config (im at), nur der define Befehl wird ausgeführt&lt;br /&gt;
*&amp;lt;code&amp;gt;define morgens at *7:00:00 set lampe1,lampe2 on&amp;lt;/code&amp;gt;   →     schaltet BEIDE Lampen immer um 7 an. Geht nur wenn der gleiche Befehl an 2 oder mehr Geräte gesendet werden soll&lt;br /&gt;
&lt;br /&gt;
=== Attribute ===&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
=== Testen ===&lt;br /&gt;
{{Randnotiz|RNText=&#039;&#039;&#039;Versionsspezifisch:&#039;&#039;&#039; Der Befehl &#039;&#039;execNow&#039;&#039; ist in FHEM 5.7/90_at.pm ab 30.4.2016 verfügbar.}}&lt;br /&gt;
Mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;set &amp;lt;devspec&amp;gt; execNow&amp;lt;/code&amp;gt;&lt;br /&gt;
lässt sich eine &#039;&#039;at&#039;&#039;-Definition (einmalig, beispielsweise zu Testzwecken) unabhängig vom Erreichen der angegebenen Zeitspezifikation ausführen.&lt;br /&gt;
&lt;br /&gt;
== Anwendungsbeispiele ==&lt;br /&gt;
* [[AT an einem bestimmten Wochentag ausführen|at an einem bestimmten Wochentag ausführen]]&lt;br /&gt;
* [[AT um eine Temperaturabhängige Nachtabsenkung zu realisieren|at um eine Temperaturabhängige Nachtabsenkung zu realisieren]]&lt;br /&gt;
* [[AT zu einem absoluten Datum ausführen|at zu einem absoluten Datum ausführen]]&lt;br /&gt;
* [[SUNRISE_EL|at in Verbindung mit SUNRISE_EL]] &lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Abfrage, ob at definiert ist: {{Link2Forum|Topic=23584|Message=841269}}&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Qnap_NAS&amp;diff=35799</id>
		<title>Qnap NAS</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Qnap_NAS&amp;diff=35799"/>
		<updated>2021-06-06T20:27:46Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* FHEM Installieren */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Randnotiz|RNTyp=Info|RNText=Ergänzungen und Aktualisierungen in {{Link2Forum|Topic=60300}} bitte beachten!}}&lt;br /&gt;
= Installation von FHEM auf einem QNAP NAS =&lt;br /&gt;
Diese Anleitung beschreibt detailiert, wie FHEM auf einer&lt;br /&gt;
QNAP Turbo Station TS-109 II pro installiert werden kann.&lt;br /&gt;
Im wesentlichen wird die Vorgehensweise auch für weitere QNAP NAS&lt;br /&gt;
gelten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Überblick ==&lt;br /&gt;
Die aktuelle QNAP Firmware 3.1.0 Build 0708 unterstützt die&lt;br /&gt;
Installation von IPKG Paketen. Sämtliche für FHEM benötigte&lt;br /&gt;
Software ist auf diese Weise verfügbar, so dass die Installation&lt;br /&gt;
eigentlich sehr einfach vonstatten gehen könnte. Leider hat QNAP&lt;br /&gt;
an einigen Stellen geschlampt und man muss von Hand etwas nachhelfen. &lt;br /&gt;
Desweiteren ist Handarbeit gefragt für folgende Zusatzfunktionen&lt;br /&gt;
&lt;br /&gt;
* Auslagerung der FHEM Logfiles auf einen Speicherstick. Somit kann die interne Festplatte weiterhin in den Spin Down gehen.&lt;br /&gt;
* Autostart von FHEM bein Booten des NAS&lt;br /&gt;
* Geordnetes Runterfahren von FHEM beim Herunterfahren des NAS&lt;br /&gt;
= Installation des QPKG Paketes Optware IPKG =&lt;br /&gt;
Über die NAS Web-Administration kann das Optware IPKG Paket&lt;br /&gt;
Optware_0.99.163_arm-x09.qpkg Installiert werden. &lt;br /&gt;
In dem Paket für die TS-109 sind leider einige Fehler enthalten, die&lt;br /&gt;
im folgenden korrigiert werden. Diese und alle weiteren Eingaben&lt;br /&gt;
sind auf der [[Kommandozeilentools|Kommandozeile]] durchzuführen.&lt;br /&gt;
&lt;br /&gt;
== Anpassen der ipkg Konfiguration ==&lt;br /&gt;
=== Namen der Konfigurationsfiles korrigieren ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cd /share/HDA_DATA/.qpkg/Optware/etc/ipkg&lt;br /&gt;
  # mv tsx19-kmod.conf tsx09-kmod.conf&lt;br /&gt;
  # mv tsx19.conf tsx09.conf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Repository für ipkg Pakete korrigieren ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# vi tsx09-kmod.conf&lt;br /&gt;
  Ändern von&lt;br /&gt;
  src tsx19 http://ipkg.nslu2-linux.org/feeds/optware/tsx19/cross/unstable&lt;br /&gt;
  in&lt;br /&gt;
  src tsx09 http://ipkg.nslu2-linux.org/feeds/optware/tsx09/cross/stable&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Repository für die ipkg Kernel Module korrigieren ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# vi tsx09.conf&lt;br /&gt;
  Ändern von&lt;br /&gt;
  src cs08q1armel http://ipkg.nslu2-linux.org/feeds/optware/cs08q1armel/cross/unstable&lt;br /&gt;
  in&lt;br /&gt;
  src cs05q3armel http://ipkg.nslu2-linux.org/feeds/optware/cs05q3armel/cross/unstable&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Zusätzliches Installationsziel für ipkg in die Config aufnehmen ===&lt;br /&gt;
Die Kernel Module werden sonst nach /lib/modules installiert, und das wird bei jedem reboot überschrieben. Also müssen sie explizit nach /opt/lib/modules installiert werden.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cd /share/HDA_DATA/.qpkg/Optware/etc&lt;br /&gt;
  # vi ipkg.conf&lt;br /&gt;
  Hinzufügen von &lt;br /&gt;
  dest opt /opt&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Anpassen des Paketnamens ===&lt;br /&gt;
Es muss überall Optware-ipkg heissen.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cd /share/HDA_DATA/.qpkg/Optware&lt;br /&gt;
  # mv Optware.sh Optware-ipkg.sh&lt;br /&gt;
  # vi Optware-ipkg.sh&lt;br /&gt;
  Ändern von&lt;br /&gt;
  QPKG_NAME=“Optware“&lt;br /&gt;
  in&lt;br /&gt;
  QPKG_NAME=“Optware-ipkg“&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Optware „mounten“ ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# /share/HDA_DATA/.qpkg/Optware/Optware-ipkg.sh restart&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Zusätzliche Software installieren =&lt;br /&gt;
Nun können die für FHEM benötigten Pakete per ipkg installiert werden.&lt;br /&gt;
&lt;br /&gt;
== Paketliste aktualisieren ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# ipkg update&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Kernel Module für USB-Serial Hardware ==&lt;br /&gt;
Das usbserial Modul unterstützt diverse USB nach seriell Wandler.&lt;br /&gt;
Für ein CUL sind keine weiteren Kernel Module nötig.&lt;br /&gt;
Ein FHT-1000 benötigt zusätzlich des ftdi-sio Modul.&lt;br /&gt;
Eine Reihe von günstigen USB nach seriell Adapterkabel benutzen den&lt;br /&gt;
Proliftic PL-2303 Chip. Hierfür ist ebenfalls ein weiteres Modul nötig.&lt;br /&gt;
Über ein solches Kabel ist dann Beispielsweise ein ELV M232 Modul anzuschliessen.&lt;br /&gt;
Neben den Kernel Modulen habe ich noch die libusb installiert. &lt;br /&gt;
Die benötige ich später einmal um einen IOWarrior anzusprechen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bei den Kernel Modulen beachten, dass diese nach /opt installiert werden.&#039;&#039;&#039;Sonst sind sie nach dem nächsten Reboot weg.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# ipkg -d opt install ts209-kernel-module-usbserial&lt;br /&gt;
  # ipkg install -d opt ts209-kernel-module-ftdi-sio&lt;br /&gt;
  # ipkg install -d opt ts209-kernel-module-pl2303&lt;br /&gt;
  # ipkg install libusb&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Kernel Module linken ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# ln -s /opt/lib/modules/2.6.12.6-arm1/kernel /lib/modules&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Module laden mit Vendor und Product ID für CUL ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# insmod /lib/modules/kernel/drivers/usb/serial/usbserial.ko vendor=0x03eb product=0x204b&lt;br /&gt;
  # insmod /lib/modules/kernel/drivers/usb/serial/ftdi_sio.ko&lt;br /&gt;
  # insmod /lib/modules/kernel/drivers/usb/serial/pl2303.ko&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Nun kann man den CUL anstöpseln und prüfen, ob er erkannt wurde&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cd /usr/local/share    # hier liegt usb.ids&lt;br /&gt;
  # lsusb&lt;br /&gt;
  Sollte u.A. folgendes ausgeben ... &lt;br /&gt;
  ID 03eb:204b Atmel Corp.&lt;br /&gt;
  # dmesg&lt;br /&gt;
  Sollte folgendes ausgeben ...&lt;br /&gt;
  usbserial_generic 2-1.4:1.1 Generic converter detected&lt;br /&gt;
  usb 2-1.4: Generic converter now attached to ttyUSB0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Benötigte Pakete für FHEM installieren ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# ipkg install perl perl-device-serialport&lt;br /&gt;
  # ipkg install make                # für die fhem Installation&lt;br /&gt;
  # ipkg install gcc                # richtige libgcc für perl&lt;br /&gt;
  # ipkg install gnuplot              # optional, falls lediglich plotmode SVG verwendet&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
= FHEM installieren =&lt;br /&gt;
FHEM am PC downloaden und in ein QNAP Public Verzeichnis auspacken z.B.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;/share/HDA_DATA/Public/TS109/fhem-4.8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Ins Download Verzeichnis wechseln ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cd /share/HDA_DATA/Public/TS109/fhem-4.8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Pfade im Makefile auf /opt/ .... ändern ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# vi Makefile&lt;br /&gt;
  BINDIR=/opt/bin&lt;br /&gt;
  MODDIR=/opt/lib&lt;br /&gt;
  VARDIR=/opt/var/log/fhem&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Logverzeichnis anlegen ==&lt;br /&gt;
Dieses Verzeichnis wird später auf einen Speicherstick ausgelagert.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# mkdir -p /opt/var/log/fhem&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Installieren ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# make install-pgm2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Pfad von Perl in fhem.pl anpassen ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# vi /opt/bin/fhem.pl&lt;br /&gt;
  #!/opt/bin/perl&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Configfile nach /opt/etc kopieren und editieren ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cp /opt/var/log/fhem/fhem.cfg /opt/etc/fhem.cfg&lt;br /&gt;
  #vi /opt/etc/fhem.cfg&lt;br /&gt;
  attr global logfile /opt/var/log/fhem/fhem-%Y-%V.log&lt;br /&gt;
  attr global statefile /opt/var/log/fhem/fhem.savestate&lt;br /&gt;
  define CUL CUL /dev/usb/ttyUSB0 &amp;amp;lt;Hauscode&amp;amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Probeweise starten ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# /opt/bin/fhem.pl /opt/etc/fhem.cfg&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Stoppen ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# killall fhem.pl&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
= Logfiles auf USB-Stick auslagern =&lt;br /&gt;
== Stick einstecken und prüfen, wo er gemounted wurde ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# mount|grep vfat&lt;br /&gt;
  /dev/sdu on /share/external/sdu type vfat&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Lokale Logfiles verschieben und verlinken ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cd /opt/var/log&lt;br /&gt;
  # cp -r fhem /share/external/sdu&lt;br /&gt;
  # mv fhem fhem.local&lt;br /&gt;
  # ln -s /share/external/sdu/fhem&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
= Autostart und Stop einrichten =&lt;br /&gt;
== Startskript anlegen ==&lt;br /&gt;
 # vi /share/HDA_DATA/.qpkg/Optware/optstart.sh&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#!/bin/sh&lt;br /&gt;
# wait for optware init&lt;br /&gt;
while ( test -z &amp;amp;quot;$(grep /opt/bin /etc/profile)&amp;amp;quot; ); do sleep 10; done&lt;br /&gt;
# get new PATH&lt;br /&gt;
source /etc/profile&lt;br /&gt;
# Execute all start scripts in /opt/etc/init.d&lt;br /&gt;
# executing them in numerical order.&lt;br /&gt;
#&lt;br /&gt;
for i in /opt/etc/init.d/S??*&amp;amp;#160;;do&lt;br /&gt;
  # Ignore dangling symlinks (if any).&lt;br /&gt;
  #[&amp;amp;#160;! -f &amp;amp;quot;$i&amp;amp;quot; ] &amp;amp;amp;&amp;amp;amp; continue&lt;br /&gt;
  case &amp;amp;quot;$i&amp;amp;quot; in&lt;br /&gt;
 *.sh)&lt;br /&gt;
  # Source shell script for speed.&lt;br /&gt;
  (&lt;br /&gt;
  trap - INT QUIT TSTP&lt;br /&gt;
  set start&lt;br /&gt;
  . $i&lt;br /&gt;
  )&lt;br /&gt;
  &amp;amp;#160;;;&lt;br /&gt;
 *)&lt;br /&gt;
  # No sh extension, so fork subprocess.&lt;br /&gt;
  $i start&lt;br /&gt;
  &amp;amp;#160;;;&lt;br /&gt;
 esac&lt;br /&gt;
done&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Startskript ausführbar machen ===&lt;br /&gt;
 # chmod a+x optstart.sh&lt;br /&gt;
&lt;br /&gt;
== Und noch einmal als Stop-Skript mit kleinen Änderungen ==&lt;br /&gt;
 # cp optstart.sh optstop.sh&lt;br /&gt;
 # chmod a+x optstop.sh&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#!/bin/sh&lt;br /&gt;
# Execute all kill scripts in /opt/etc/init.d&lt;br /&gt;
# executing them in numerical order.&lt;br /&gt;
#&lt;br /&gt;
for i in /opt/etc/init.d/K??*&amp;amp;#160;;do&lt;br /&gt;
  # Ignore dangling symlinks (if any).&lt;br /&gt;
  #[&amp;amp;#160;! -f &amp;amp;quot;$i&amp;amp;quot; ] &amp;amp;amp;&amp;amp;amp; continue&lt;br /&gt;
  case &amp;amp;quot;$i&amp;amp;quot; in&lt;br /&gt;
 *.sh)&lt;br /&gt;
  # Source shell script for speed.&lt;br /&gt;
  (&lt;br /&gt;
  trap - INT QUIT TSTP&lt;br /&gt;
  set stop&lt;br /&gt;
  . $i&lt;br /&gt;
  )&lt;br /&gt;
  &amp;amp;#160;;;&lt;br /&gt;
 *)&lt;br /&gt;
  # No sh extension, so fork subprocess.&lt;br /&gt;
  $i stop&lt;br /&gt;
  &amp;amp;#160;;;&lt;br /&gt;
 esac&lt;br /&gt;
done&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Start- und Stop-Skript aus Optware-ipkg.sh heraus aufrufen ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cd /etc/init.d&lt;br /&gt;
  # vi Optware-ipkg.sh&lt;br /&gt;
  Die Sektion in start/stop folgendermassen anpassen&lt;br /&gt;
  &lt;br /&gt;
  case &amp;amp;quot;$1&amp;amp;quot; in&lt;br /&gt;
   start)&lt;br /&gt;
      /bin/echo &amp;amp;quot;Enable Optware/ipkg&amp;amp;quot;&lt;br /&gt;
      # sym-link $QPKG_DIR to /opt&lt;br /&gt;
      /bin/rm -rf /opt&lt;br /&gt;
      /bin/ln -sf $QPKG_DIR /opt&lt;br /&gt;
      # adding Ipkg apps into system path ...&lt;br /&gt;
      /bin/cat /etc/profile | /bin/grep &amp;amp;quot;PATH&amp;amp;quot; | /bin/grep &amp;amp;quot;/opt/bin&amp;amp;quot; \&lt;br /&gt;
   		1&amp;amp;gt;&amp;amp;gt;/dev/null 2&amp;amp;gt;&amp;amp;gt;/dev/null&lt;br /&gt;
      [ $? -ne 0 ] &amp;amp;amp;&amp;amp;amp; /bin/echo &amp;amp;quot;export PATH=$PATH&amp;amp;quot;:/opt/bin:/opt/sbin \&lt;br /&gt;
  		&amp;amp;gt;&amp;amp;gt; /etc/profile&lt;br /&gt;
      if [ -x /opt/optstart.sh ]; then&lt;br /&gt;
          /opt/optstart.sh&lt;br /&gt;
      fi&lt;br /&gt;
      &amp;amp;#160;;;&lt;br /&gt;
   stop)&lt;br /&gt;
      /bin/echo &amp;amp;quot;Disable Optware/ipkg&amp;amp;quot;&lt;br /&gt;
      if [ -x /opt/optstop.sh ]; then&lt;br /&gt;
          /opt/optstop.sh&lt;br /&gt;
      fi&lt;br /&gt;
      export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin&lt;br /&gt;
      /bin/sync&lt;br /&gt;
      /bin/sleep 1&lt;br /&gt;
      &amp;amp;#160;;;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== FHEM Init-Skript anlegen ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cp /share/HDA_DATA/Public/TS109/fhem-4.8/contrib/init-skripts/fhem.2 \&lt;br /&gt;
  	/opt/etc/init.s/init_fhem&lt;br /&gt;
  # vi /opt/etc/init.d/init_fhem&lt;br /&gt;
  #!/bin/sh&lt;br /&gt;
  # by Matthias Bauer&lt;br /&gt;
  case &amp;amp;quot;$1&amp;amp;quot; in&lt;br /&gt;
   start)&lt;br /&gt;
    echo &amp;amp;quot;Starting $0&amp;amp;quot;&lt;br /&gt;
    /opt/bin/fhem.pl /opt/etc/fhem.cfg&lt;br /&gt;
    &amp;amp;#160;;;&lt;br /&gt;
   stop)&lt;br /&gt;
    echo &amp;amp;quot;Stopping $0&amp;amp;quot;&lt;br /&gt;
    /opt/bin/fhem.pl 7072 shutdown&lt;br /&gt;
    &amp;amp;#160;;;&lt;br /&gt;
   status)&lt;br /&gt;
    cnt=`ps -ef | grep &amp;amp;quot;fhem.pl&amp;amp;quot; | grep -v grep | wc -l`&lt;br /&gt;
    if [ &amp;amp;quot;$cnt&amp;amp;quot; -eq &amp;amp;quot;0&amp;amp;quot; ]&amp;amp;#160;; then&lt;br /&gt;
     echo &amp;amp;quot;$0 is not running&amp;amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
     echo &amp;amp;quot;$0 is running&amp;amp;quot;&lt;br /&gt;
    fi&lt;br /&gt;
    &amp;amp;#160;;;&lt;br /&gt;
   *)&lt;br /&gt;
    echo &amp;amp;quot;Usage: $0 {start|stop|status}&amp;amp;quot;&lt;br /&gt;
   exit 1&lt;br /&gt;
  esac&lt;br /&gt;
  exit 0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Ausführbar machen und Links anlegen ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# chmod u+x init_fhem&lt;br /&gt;
  # ln -s init_fhem S30fhem&lt;br /&gt;
  # ln -s init_fhem K10fhem&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Startskript zum Laden der USB-Serial Kernel Module anlegen ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# vi S01kernel-modules&lt;br /&gt;
  #!/bin/sh&lt;br /&gt;
  ln -s /opt/lib/modules/2.6.12.6-arm1/kernel /lib/modules&lt;br /&gt;
  insmod /lib/modules/kernel/drivers/usb/serial/usbserial.ko vendor=0x03eb product=0x204b&lt;br /&gt;
  insmod /lib/modules/kernel/drivers/usb/serial/ftdi_sio.ko&lt;br /&gt;
  insmod /lib/modules/kernel/drivers/usb/serial/pl2303.ko&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Ausführbar machen ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# chmod u+x S01kernel-modules&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
= Reboot und Test =&lt;br /&gt;
Viel Spass&lt;br /&gt;
&lt;br /&gt;
TorstenS 06.03.2010&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:Server Hardware]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Qnap_NAS&amp;diff=35798</id>
		<title>Qnap NAS</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Qnap_NAS&amp;diff=35798"/>
		<updated>2021-06-06T20:25:12Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Benötigte Pakete für fhem insatllieren */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Randnotiz|RNTyp=Info|RNText=Ergänzungen und Aktualisierungen in {{Link2Forum|Topic=60300}} bitte beachten!}}&lt;br /&gt;
= Installation von FHEM auf einem QNAP NAS =&lt;br /&gt;
Diese Anleitung beschreibt detailiert, wie FHEM auf einer&lt;br /&gt;
QNAP Turbo Station TS-109 II pro installiert werden kann.&lt;br /&gt;
Im wesentlichen wird die Vorgehensweise auch für weitere QNAP NAS&lt;br /&gt;
gelten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Überblick ==&lt;br /&gt;
Die aktuelle QNAP Firmware 3.1.0 Build 0708 unterstützt die&lt;br /&gt;
Installation von IPKG Paketen. Sämtliche für FHEM benötigte&lt;br /&gt;
Software ist auf diese Weise verfügbar, so dass die Installation&lt;br /&gt;
eigentlich sehr einfach vonstatten gehen könnte. Leider hat QNAP&lt;br /&gt;
an einigen Stellen geschlampt und man muss von Hand etwas nachhelfen. &lt;br /&gt;
Desweiteren ist Handarbeit gefragt für folgende Zusatzfunktionen&lt;br /&gt;
&lt;br /&gt;
* Auslagerung der FHEM Logfiles auf einen Speicherstick. Somit kann die interne Festplatte weiterhin in den Spin Down gehen.&lt;br /&gt;
* Autostart von FHEM bein Booten des NAS&lt;br /&gt;
* Geordnetes Runterfahren von FHEM beim Herunterfahren des NAS&lt;br /&gt;
= Installation des QPKG Paketes Optware IPKG =&lt;br /&gt;
Über die NAS Web-Administration kann das Optware IPKG Paket&lt;br /&gt;
Optware_0.99.163_arm-x09.qpkg Installiert werden. &lt;br /&gt;
In dem Paket für die TS-109 sind leider einige Fehler enthalten, die&lt;br /&gt;
im folgenden korrigiert werden. Diese und alle weiteren Eingaben&lt;br /&gt;
sind auf der [[Kommandozeilentools|Kommandozeile]] durchzuführen.&lt;br /&gt;
&lt;br /&gt;
== Anpassen der ipkg Konfiguration ==&lt;br /&gt;
=== Namen der Konfigurationsfiles korrigieren ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cd /share/HDA_DATA/.qpkg/Optware/etc/ipkg&lt;br /&gt;
 # mv tsx19-kmod.conf tsx09-kmod.conf&lt;br /&gt;
 # mv tsx19.conf tsx09.conf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Repository für ipkg Pakete korrigieren ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# vi tsx09-kmod.conf&lt;br /&gt;
 Ändern von&lt;br /&gt;
 src tsx19 http://ipkg.nslu2-linux.org/feeds/optware/tsx19/cross/unstable&lt;br /&gt;
 in&lt;br /&gt;
 src tsx09 http://ipkg.nslu2-linux.org/feeds/optware/tsx09/cross/stable&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Repository für die ipkg Kernel Module korrigieren ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# vi tsx09.conf&lt;br /&gt;
 Ändern von&lt;br /&gt;
 src cs08q1armel http://ipkg.nslu2-linux.org/feeds/optware/cs08q1armel/cross/unstable&lt;br /&gt;
 in&lt;br /&gt;
 src cs05q3armel http://ipkg.nslu2-linux.org/feeds/optware/cs05q3armel/cross/unstable&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Zusätzliches Installationsziel für ipkg in die Config aufnehmen ===&lt;br /&gt;
Die Kernel Module werden sonst nach /lib/modules installiert, und das wird bei jedem reboot überschrieben. Also müssen sie explizit nach /opt/lib/modules installiert werden.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cd /share/HDA_DATA/.qpkg/Optware/etc&lt;br /&gt;
 # vi ipkg.conf&lt;br /&gt;
 Hinzufügen von &lt;br /&gt;
 dest opt /opt&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Anpassen des Paketnamens ===&lt;br /&gt;
Es muss überall Optware-ipkg heissen.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cd /share/HDA_DATA/.qpkg/Optware&lt;br /&gt;
 # mv Optware.sh Optware-ipkg.sh&lt;br /&gt;
 # vi Optware-ipkg.sh&lt;br /&gt;
 Ändern von&lt;br /&gt;
 QPKG_NAME=“Optware“&lt;br /&gt;
 in&lt;br /&gt;
 QPKG_NAME=“Optware-ipkg“&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Optware „mounten“ ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# /share/HDA_DATA/.qpkg/Optware/Optware-ipkg.sh restart&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Zusätzliche Software installieren =&lt;br /&gt;
Nun können die für FHEM benötigten Pakete per ipkg installiert werden.&lt;br /&gt;
&lt;br /&gt;
== Paketliste aktualisieren ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# ipkg update&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Kernel Module für USB-Serial Hardware ==&lt;br /&gt;
Das usbserial Modul unterstützt diverse USB nach seriell Wandler.&lt;br /&gt;
Für ein CUL sind keine weiteren Kernel Module nötig.&lt;br /&gt;
Ein FHT-1000 benötigt zusätzlich des ftdi-sio Modul.&lt;br /&gt;
Eine Reihe von günstigen USB nach seriell Adapterkabel benutzen den&lt;br /&gt;
Proliftic PL-2303 Chip. Hierfür ist ebenfalls ein weiteres Modul nötig.&lt;br /&gt;
Über ein solches Kabel ist dann Beispielsweise ein ELV M232 Modul anzuschliessen.&lt;br /&gt;
Neben den Kernel Modulen habe ich noch die libusb installiert. &lt;br /&gt;
Die benötige ich später einmal um einen IOWarrior anzusprechen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bei den Kernel Modulen beachten, dass diese nach /opt installiert werden.&#039;&#039;&#039;Sonst sind sie nach dem nächsten Reboot weg.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# ipkg -d opt install ts209-kernel-module-usbserial&lt;br /&gt;
 # ipkg install -d opt ts209-kernel-module-ftdi-sio&lt;br /&gt;
 # ipkg install -d opt ts209-kernel-module-pl2303&lt;br /&gt;
 # ipkg install libusb&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Kernel Module linken ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# ln -s /opt/lib/modules/2.6.12.6-arm1/kernel /lib/modules&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Module laden mit Vendor und Product ID für CUL ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# insmod /lib/modules/kernel/drivers/usb/serial/usbserial.ko vendor=0x03eb product=0x204b&lt;br /&gt;
 # insmod /lib/modules/kernel/drivers/usb/serial/ftdi_sio.ko&lt;br /&gt;
 # insmod /lib/modules/kernel/drivers/usb/serial/pl2303.ko&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Nun kann man den CUL anstöpseln und prüfen, ob er erkannt wurde&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cd /usr/local/share    # hier liegt usb.ids&lt;br /&gt;
 # lsusb&lt;br /&gt;
 Sollte u.A. folgendes ausgeben ... &lt;br /&gt;
 ID 03eb:204b Atmel Corp.&lt;br /&gt;
 # dmesg&lt;br /&gt;
 Sollte folgendes ausgeben ...&lt;br /&gt;
 usbserial_generic 2-1.4:1.1 Generic converter detected&lt;br /&gt;
 usb 2-1.4: Generic converter now attached to ttyUSB0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Benötigte Pakete für FHEM installieren ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# ipkg install perl perl-device-serialport&lt;br /&gt;
 # ipkg install make                # für die fhem Installation&lt;br /&gt;
 # ipkg install gcc                # richtige libgcc für perl&lt;br /&gt;
 # ipkg install gnuplot              # optional, falls lediglich plotmode SVG verwendet&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
= FHEM Installieren =&lt;br /&gt;
FHEM am PC downloaden und in ein QNAP Public Verzeichniss auspacken z.B.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;/share/HDA_DATA/Public/TS109/fhem-4.8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Ins Download Verzeichniss wechseln ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cd /share/HDA_DATA/Public/TS109/fhem-4.8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Pfade im Makefile auf /opt/ .... ändern ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# vi Makefile&lt;br /&gt;
 BINDIR=/opt/bin&lt;br /&gt;
 MODDIR=/opt/lib&lt;br /&gt;
 VARDIR=/opt/var/log/fhem&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Logverzeichniss anlegen ==&lt;br /&gt;
Dieses Verzeichniss wird später auf einen Speicherstick ausgelagert.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# mkdir -p /opt/var/log/fhem&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Installieren ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# make install-pgm2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Pfad von perl in fhem.pl anpassen ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# vi /opt/bin/fhem.pl&lt;br /&gt;
 #!/opt/bin/perl&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Konfigfile nach /opt/etc kopieren und editieren ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cp /opt/var/log/fhem/fhem.cfg /opt/etc/fhem.cfg&lt;br /&gt;
 #vi /opt/etc/fhem.cfg&lt;br /&gt;
 attr global logfile /opt/var/log/fhem/fhem-%Y-%V.log&lt;br /&gt;
 attr global statefile /opt/var/log/fhem/fhem.savestate&lt;br /&gt;
 define CUL CUL /dev/usb/ttyUSB0 &amp;amp;lt;Hauscode&amp;amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Probeweise starten ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# /opt/bin/fhem.pl /opt/etc/fhem.cfg&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Stoppen ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# killall fhem.pl&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
= Logfiles auf USB-Stick auslagern =&lt;br /&gt;
== Stick anstöpseln und prüfen, wo er gemounted wurde ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# mount|grep vfat&lt;br /&gt;
 /dev/sdu on /share/external/sdu type vfat&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Lokale Logfiles verschieben und verlinken ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cd /opt/var/log&lt;br /&gt;
 # cp -r fhem /share/external/sdu&lt;br /&gt;
 # mv fhem fhem.local&lt;br /&gt;
 # ln -s /share/external/sdu/fhem&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
= Autostart und Stop einrichten =&lt;br /&gt;
== Startskript anlegen ==&lt;br /&gt;
 # vi /share/HDA_DATA/.qpkg/Optware/optstart.sh&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#!/bin/sh&lt;br /&gt;
# wait for optware init&lt;br /&gt;
while ( test -z &amp;amp;quot;$(grep /opt/bin /etc/profile)&amp;amp;quot; ); do sleep 10; done&lt;br /&gt;
# get new PATH&lt;br /&gt;
source /etc/profile&lt;br /&gt;
# Execute all start scripts in /opt/etc/init.d&lt;br /&gt;
# executing them in numerical order.&lt;br /&gt;
#&lt;br /&gt;
for i in /opt/etc/init.d/S??*&amp;amp;#160;;do&lt;br /&gt;
  # Ignore dangling symlinks (if any).&lt;br /&gt;
  #[&amp;amp;#160;! -f &amp;amp;quot;$i&amp;amp;quot; ] &amp;amp;amp;&amp;amp;amp; continue&lt;br /&gt;
  case &amp;amp;quot;$i&amp;amp;quot; in&lt;br /&gt;
 *.sh)&lt;br /&gt;
  # Source shell script for speed.&lt;br /&gt;
  (&lt;br /&gt;
  trap - INT QUIT TSTP&lt;br /&gt;
  set start&lt;br /&gt;
  . $i&lt;br /&gt;
  )&lt;br /&gt;
  &amp;amp;#160;;;&lt;br /&gt;
 *)&lt;br /&gt;
  # No sh extension, so fork subprocess.&lt;br /&gt;
  $i start&lt;br /&gt;
  &amp;amp;#160;;;&lt;br /&gt;
 esac&lt;br /&gt;
done&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Startskript ausführbar machen ===&lt;br /&gt;
 # chmod a+x optstart.sh&lt;br /&gt;
&lt;br /&gt;
== Und noch einmal als Stopskript mit kleinen Änderungen ==&lt;br /&gt;
 # cp optstart.sh optstop.sh&lt;br /&gt;
 # chmod a+x optstop.sh&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#!/bin/sh&lt;br /&gt;
# Execute all kill scripts in /opt/etc/init.d&lt;br /&gt;
# executing them in numerical order.&lt;br /&gt;
#&lt;br /&gt;
for i in /opt/etc/init.d/K??*&amp;amp;#160;;do&lt;br /&gt;
  # Ignore dangling symlinks (if any).&lt;br /&gt;
  #[&amp;amp;#160;! -f &amp;amp;quot;$i&amp;amp;quot; ] &amp;amp;amp;&amp;amp;amp; continue&lt;br /&gt;
  case &amp;amp;quot;$i&amp;amp;quot; in&lt;br /&gt;
 *.sh)&lt;br /&gt;
  # Source shell script for speed.&lt;br /&gt;
  (&lt;br /&gt;
  trap - INT QUIT TSTP&lt;br /&gt;
  set stop&lt;br /&gt;
  . $i&lt;br /&gt;
  )&lt;br /&gt;
  &amp;amp;#160;;;&lt;br /&gt;
 *)&lt;br /&gt;
  # No sh extension, so fork subprocess.&lt;br /&gt;
  $i stop&lt;br /&gt;
  &amp;amp;#160;;;&lt;br /&gt;
 esac&lt;br /&gt;
done&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Start- und Stopskript aus Optware-ipkg.sh heraus aufrufen ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cd /etc/init.d&lt;br /&gt;
 # vi Optware-ipkg.sh&lt;br /&gt;
 Die Sektion in start/stop folgendermassen anpassen&lt;br /&gt;
 &lt;br /&gt;
 case &amp;amp;quot;$1&amp;amp;quot; in&lt;br /&gt;
  start)&lt;br /&gt;
     /bin/echo &amp;amp;quot;Enable Optware/ipkg&amp;amp;quot;&lt;br /&gt;
     # sym-link $QPKG_DIR to /opt&lt;br /&gt;
     /bin/rm -rf /opt&lt;br /&gt;
     /bin/ln -sf $QPKG_DIR /opt&lt;br /&gt;
     # adding Ipkg apps into system path ...&lt;br /&gt;
     /bin/cat /etc/profile | /bin/grep &amp;amp;quot;PATH&amp;amp;quot; | /bin/grep &amp;amp;quot;/opt/bin&amp;amp;quot; \&lt;br /&gt;
  		1&amp;amp;gt;&amp;amp;gt;/dev/null 2&amp;amp;gt;&amp;amp;gt;/dev/null&lt;br /&gt;
     [ $? -ne 0 ] &amp;amp;amp;&amp;amp;amp; /bin/echo &amp;amp;quot;export PATH=$PATH&amp;amp;quot;:/opt/bin:/opt/sbin \&lt;br /&gt;
 		&amp;amp;gt;&amp;amp;gt; /etc/profile&lt;br /&gt;
     if [ -x /opt/optstart.sh ]; then&lt;br /&gt;
         /opt/optstart.sh&lt;br /&gt;
     fi&lt;br /&gt;
     &amp;amp;#160;;;&lt;br /&gt;
  stop)&lt;br /&gt;
     /bin/echo &amp;amp;quot;Disable Optware/ipkg&amp;amp;quot;&lt;br /&gt;
     if [ -x /opt/optstop.sh ]; then&lt;br /&gt;
         /opt/optstop.sh&lt;br /&gt;
     fi&lt;br /&gt;
     export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin&lt;br /&gt;
     /bin/sync&lt;br /&gt;
     /bin/sleep 1&lt;br /&gt;
     &amp;amp;#160;;;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== FHEM Initskript anlegen ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# cp /share/HDA_DATA/Public/TS109/fhem-4.8/contrib/init-skripts/fhem.2 \&lt;br /&gt;
 	/opt/etc/init.s/init_fhem&lt;br /&gt;
 # vi /opt/etc/init.d/init_fhem&lt;br /&gt;
 #!/bin/sh&lt;br /&gt;
 # by Matthias Bauer&lt;br /&gt;
 case &amp;amp;quot;$1&amp;amp;quot; in&lt;br /&gt;
  start)&lt;br /&gt;
   echo &amp;amp;quot;Starting $0&amp;amp;quot;&lt;br /&gt;
   /opt/bin/fhem.pl /opt/etc/fhem.cfg&lt;br /&gt;
   &amp;amp;#160;;;&lt;br /&gt;
  stop)&lt;br /&gt;
   echo &amp;amp;quot;Stopping $0&amp;amp;quot;&lt;br /&gt;
   /opt/bin/fhem.pl 7072 shutdown&lt;br /&gt;
   &amp;amp;#160;;;&lt;br /&gt;
  status)&lt;br /&gt;
   cnt=`ps -ef | grep &amp;amp;quot;fhem.pl&amp;amp;quot; | grep -v grep | wc -l`&lt;br /&gt;
   if [ &amp;amp;quot;$cnt&amp;amp;quot; -eq &amp;amp;quot;0&amp;amp;quot; ]&amp;amp;#160;; then&lt;br /&gt;
    echo &amp;amp;quot;$0 is not running&amp;amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
    echo &amp;amp;quot;$0 is running&amp;amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
   &amp;amp;#160;;;&lt;br /&gt;
  *)&lt;br /&gt;
   echo &amp;amp;quot;Usage: $0 {start|stop|status}&amp;amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
 esac&lt;br /&gt;
 exit 0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Ausführbar machen und Links anlegen ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# chmod u+x init_fhem&lt;br /&gt;
 # ln -s init_fhem S30fhem&lt;br /&gt;
 # ln -s init_fhem K10fhem&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
== Startskript zum Laden der Usb-serial Kernel Module anlegen ==&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# vi S01kernel-modules&lt;br /&gt;
 #!/bin/sh&lt;br /&gt;
 ln -s /opt/lib/modules/2.6.12.6-arm1/kernel /lib/modules&lt;br /&gt;
 insmod /lib/modules/kernel/drivers/usb/serial/usbserial.ko vendor=0x03eb product=0x204b&lt;br /&gt;
 insmod /lib/modules/kernel/drivers/usb/serial/ftdi_sio.ko&lt;br /&gt;
 insmod /lib/modules/kernel/drivers/usb/serial/pl2303.ko&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
=== Ausführbar machen ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# chmod u+x S01kernel-modules&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
= Reboot und Test =&lt;br /&gt;
Viel Spass&lt;br /&gt;
&lt;br /&gt;
TorstenS 06.03.2010&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:Server Hardware]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=VALVES&amp;diff=35708</id>
		<title>VALVES</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=VALVES&amp;diff=35708"/>
		<updated>2021-05-10T18:13:22Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Auch hier nur Schreibfehler bereinigt */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Modul&lt;br /&gt;
|ModPurpose=Durchschnitt mit individueller Gewichtung und Ignore&lt;br /&gt;
&amp;lt;!-- |ModCategory= (noch?) nicht verwendet --&amp;gt;&lt;br /&gt;
|ModType=x&lt;br /&gt;
&amp;lt;!-- |ModCmdRef= ---- noch nicht Teil von FHEM --&amp;gt;&lt;br /&gt;
|ModForumArea=Codeschnipsel&lt;br /&gt;
|ModTechName=39_VALVES.pm&lt;br /&gt;
|ModOwner=epsrw1,cwagner}}&lt;br /&gt;
[[VALVES]] bietet eine einfache Möglichkeit, den nach flexibel konfigurierbaren Regeln gewichteten Durchschnittswert einer Gruppe von Werten zu berechnen.&lt;br /&gt;
&lt;br /&gt;
== Features ==&lt;br /&gt;
&amp;lt;u&amp;gt;Diese Wiki-Seite beschreibt den Versionsstand 1.0 des VALVES-Moduls.&amp;lt;/u&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Die Namensgebung beruht auf der primären Anwendung des Moduls auf Valve-Position-Readings von Heizungsthermostaten.&lt;br /&gt;
&lt;br /&gt;
Thread im Forum:{{Link2Forum|Topic=24658|Message=177528}}&lt;br /&gt;
&lt;br /&gt;
== Beschreibung ==&lt;br /&gt;
[[Datei:dok39_VALVES.jpg|mini|Funktionsweise]]&lt;br /&gt;
&lt;br /&gt;
VALVES bietet als kleines Helferlein die Möglichkeit, einen halbwegs sinnvollen und individuell gewichteten Durchschnittswert der Readings mehrerer verschiedener Devices zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Für jeden Wert einzeln kann ein Offset definiert werden. Es können dynamisch jeweils die höchsten/niedrigsten 0 bis 3 Werte ignoriert werden. Eine weitere Einstellung ermöglicht, bestimmte Werte doppelt zu zählen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Im Anwendungsbeispiel [[Raumbedarfsabhängige Heizungssteuerung]] wird das Modul zum Beispiel verwendet, um den Durchschnittswert der Ventilöffnungen aller Heizkörper zu berechnen. Die individuelle Gewichtung über Attr ermöglicht hierbei einen virtuellen hydraulischen Abgleich.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die Liste aller auszulesenden Devices wird in einem ATTR eingestellt, der Name des Readings in einem weiteren. Das Modul prüft dann regelmäßig (attr: poll interval) die Daten der FHEM-Devices und berechnet neu, wenn ein Änderung festgestellt wird.&lt;br /&gt;
&lt;br /&gt;
Für die Beeinflussung des Durchschnittes hat man folgende Attribute:&lt;br /&gt;
&lt;br /&gt;
* ignoriere niedrigste 0...3 Positionen&lt;br /&gt;
&lt;br /&gt;
* ignoriere höchste 0...3 Positionen&lt;br /&gt;
&lt;br /&gt;
* ignoriere namentlich genannte Devices&lt;br /&gt;
&lt;br /&gt;
* priority-device Liste (zählen doppelt)&lt;br /&gt;
&lt;br /&gt;
* valves&amp;lt;Devicename&amp;gt;Gewichtung optionale Einzeleinstellung für jedes Reading, multipliziere mit Attr-Wert (zB:0,95 um 5% abzuziehen). Damit können Unterschiede bekannte gleichbleibende Meßungenauigkeiten kompensiert werden, oder verschieden große Geräte in vergleichbare Rechengrößen konvertiert werden.&lt;br /&gt;
&lt;br /&gt;
== Define ==&lt;br /&gt;
:&amp;lt;code&amp;gt;define &amp;lt;name&amp;gt; VALVES &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Alle Attribute sind auch in FHEM durch das Kommando get attrHelp &amp;lt;varname&amp;gt; erklärt, fürs &amp;quot;schnelle Nachschauen zwischendurch&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
valvesInitialDelay -&amp;gt; Startverzögerung&lt;br /&gt;
&lt;br /&gt;
valvesPollInterval -&amp;gt; Berechnungsfrequenz&lt;br /&gt;
&lt;br /&gt;
valvesDeviceList -&amp;gt; &#039;&#039;&#039;Pflicht-Attr&#039;&#039;&#039;, Liste Thermostate mit valve-pos Readings&lt;br /&gt;
&lt;br /&gt;
valvesDeviceReading -&amp;gt; &#039;&#039;&#039;Pflicht-Attr&#039;&#039;&#039;, Bezeichnung valve-pos Reading&lt;br /&gt;
&lt;br /&gt;
valvesIgnoreLowest -&amp;gt; Niedrigste N Werte ignorieren&lt;br /&gt;
&lt;br /&gt;
valvesIgnoreHighest -&amp;gt; Höchste N Werte ignorieren&lt;br /&gt;
&lt;br /&gt;
valvesIgnoreDeviceList -&amp;gt; Device(s) die komplett ignoriert werden, z.B. temporärer Eintrag für Gästezimmer&lt;br /&gt;
&lt;br /&gt;
valvesPriorityDeviceList -&amp;gt; Devices, die doppelt gezählt werden&lt;br /&gt;
&lt;br /&gt;
valves&amp;lt;Devicename&amp;gt; Gewichtung -&amp;gt; Faktor für einzelnes Device für individuelle Gewichtung&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
reset -&amp;gt; Alle Readings zurücksetzen&lt;br /&gt;
&lt;br /&gt;
== Readings ==&lt;br /&gt;
state -&amp;gt; Fehlermeldung oder Mittelwert nach oben beschriebener Berechnung&lt;br /&gt;
&lt;br /&gt;
valve_&amp;lt;Devicename&amp;gt; -&amp;gt; Berechnete virtuelle Ventilstellung pro Gerät&lt;br /&gt;
&lt;br /&gt;
valveDetail_&amp;lt;Devicename&amp;gt; -&amp;gt; Debug-Info mit Details&lt;br /&gt;
&lt;br /&gt;
raw_average -&amp;gt; Simpler Mittelwert ohne Berücksichtigung der Gewichtungen (ignores werden auch hier ignoriert)&lt;br /&gt;
&lt;br /&gt;
valve_average -&amp;gt; Mittelwert nach oben beschriebener Berechnung&lt;br /&gt;
&lt;br /&gt;
valve_max -&amp;gt; Größte aktuelle Ventilöffnung seit letztem Reset&lt;br /&gt;
&lt;br /&gt;
valve_min -&amp;gt; Kleinste aktuelle Ventilöffnung seit letztem Reset&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* {{Link2Forum|Topic=24658|Message=177528}} Thread im Forum, in dem dieses Modul vorgestellt wurde&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Regelungstechnik]]&lt;br /&gt;
[[Kategorie:Heizungssteuerung]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Raumbedarfsabh%C3%A4ngige_Heizungssteuerung&amp;diff=35707</id>
		<title>Raumbedarfsabhängige Heizungssteuerung</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Raumbedarfsabh%C3%A4ngige_Heizungssteuerung&amp;diff=35707"/>
		<updated>2021-05-10T18:07:46Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Schreibfehler bereinigt */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Modul&lt;br /&gt;
|ModPurpose=Dieses Modul ist noch Entwicklung&lt;br /&gt;
|ModType=x&lt;br /&gt;
&amp;lt;!-- |ModCategory= (noch?) nicht verwendet --&amp;gt;&lt;br /&gt;
&amp;lt;!-- |ModCmdRef= ---- noch nicht Teil von FHEM --&amp;gt;&lt;br /&gt;
|ModForumArea=Codeschnipsel&lt;br /&gt;
|ModTechName=39_VALVES.pm&lt;br /&gt;
|ModOwner=epsrw1,cwagner}}&lt;br /&gt;
&lt;br /&gt;
Das FHEM-[[:Kategorie:Hilfsmodul|Hilfsmodul]] [[VALVES]] bietet eine einfache Möglichkeit, eine raumbedarfsabhängige Steuerung des Vorlaufes (Brenner oder Mischer, dazu siehe auch [[Mischersteuerung]]) einer Zentralheizung umzusetzen. Diese berücksichtigt besser als eine Außentemperatursteuerung interne und externe Wärmequellen. &lt;br /&gt;
&lt;br /&gt;
== Features ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Diese Wiki-Seite beschreibt den derzeitigen Stand des VALVES-Moduls.&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Thread im Forum:{{Link2Forum|Topic=24658|Message=177528}}&lt;br /&gt;
&lt;br /&gt;
== Beschreibung ==&lt;br /&gt;
&lt;br /&gt;
[[Datei:dok39_VALVES.jpg|mini|Funktionsweise]]&lt;br /&gt;
VALVES bietet als kleines Helferlein die Möglichkeit, einen halbwegs sinnvollen und individuell gewichteten Durchschnittswert der Ventilpositionen mehrerer Heizungsthermostate zu berechnen.&lt;br /&gt;
&lt;br /&gt;
Dieser (gewichtete) Durchschnittswert der Ventilöffnungen ist ein Ausdruck der Wärmeanforderung im Haus. Da die Raumthermostate aus der FS20-, der Homematic und der Max-Reihe ihrerseits immer bessere Strategien verfolgen, um die Entwicklung der Temperatur in jeweils &amp;quot;ihrem&amp;quot; Raum zu erkennen, hat die Ventilposition eine große Aussagekraft.&lt;br /&gt;
&lt;br /&gt;
Zugleich wird auch Vorlaufsteuerung des Heizkessels oder der Heiztherme automatisch durch Nachtabsenkungen, Abwesentheitsschaltungen einerseits und durch zusätzliche Wärmequellen, die das Haus aufheizen, beeinflusst.&lt;br /&gt;
&lt;br /&gt;
Idealerweise ist der Vorlauf dann gerade so groß, dass der Wärmebedarf im Haus überall gestillt wird.&lt;br /&gt;
&lt;br /&gt;
Die Liste aller Thermostate wird in einem ATTR eingestellt, der Name des Readings mit der Ventilposition in einem weiteren. Das Modul prüft dann regelmäßig (attr: poll interval) die Daten des FHEM-Devices und berechnet neu, wenn ein Änderung festgestellt wird.&lt;br /&gt;
&lt;br /&gt;
Für die Beeinflussung des Durchschnittes hat man folgende Attribute:&lt;br /&gt;
&lt;br /&gt;
* ignoriere niedrigste 0...3 Positionen&lt;br /&gt;
&lt;br /&gt;
* ignoriere höchste 0...3 Positionen&lt;br /&gt;
&lt;br /&gt;
* ignoriere namentlich genannte Devices&lt;br /&gt;
&lt;br /&gt;
* priority-device Liste (zählen doppelt)&lt;br /&gt;
&lt;br /&gt;
* valves&amp;lt;Devicename&amp;gt;Gewichtung optionale Einzeleinstellung für jeden Thermostat, multipliziere mit attr-wert (zB:0,95 um 5% der Position abzuziehen). Damit können Unterschiede im hydraulischen Abgleich kompensiert werden, oder individuelles Nutzungsverhalten feinjustiert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Define ==&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  define &amp;lt;name&amp;gt; VALVES  &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Alle Attributes sind auch in FHEM durch das Kommando get attrHelp &amp;lt;varname&amp;gt; erklärt, fürs &amp;quot;schnelle Nachschauen zwischendurch&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
valvesInitialDelay -&amp;gt; Startverzögerung&lt;br /&gt;
&lt;br /&gt;
valvesPollInterval -&amp;gt; Berechnungsfrequenz&lt;br /&gt;
&lt;br /&gt;
valvesDeviceList -&amp;gt; &#039;&#039;&#039;Pflicht-Attr&#039;&#039;&#039;, Liste &amp;gt;Thermostate mit valve-pos Readings&lt;br /&gt;
&lt;br /&gt;
valvesDeviceReading -&amp;gt; &#039;&#039;&#039;Pflicht-Attr&#039;&#039;&#039;, Bezeichnung valve-pos Reading&lt;br /&gt;
&lt;br /&gt;
valvesIgnoreLowest -&amp;gt; Niedrigste N Werte ignorieren&lt;br /&gt;
&lt;br /&gt;
valvesIgnoreHighest -&amp;gt; Höchste N Werte ignorieren&lt;br /&gt;
&lt;br /&gt;
valvesIgnoreDeviceList -&amp;gt; Device(s) die komplett ignoriert werden, z.B. temporärer Eintrag für Gästezimmer&lt;br /&gt;
&lt;br /&gt;
valvesPriorityDeviceList -&amp;gt; Devices, die doppelt gezählt werden&lt;br /&gt;
&lt;br /&gt;
valves&amp;lt;Devicename&amp;gt;Gewichtung -&amp;gt; Faktor für einzelnes Device für individuelle Gewichtung&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
reset -&amp;gt; Alle Readings zurücksetzen&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Readings ==&lt;br /&gt;
&lt;br /&gt;
state -&amp;gt; Fehlermeldung oder Mittelwert nach oben beschriebener Berechnung&lt;br /&gt;
&lt;br /&gt;
valve_&amp;lt;Devicename&amp;gt; -&amp;gt; Berechnete virtuelle Ventilstellung pro Gerät&lt;br /&gt;
&lt;br /&gt;
valveDetail_&amp;lt;Devicename&amp;gt; -&amp;gt; Debug-Info mit Details&lt;br /&gt;
&lt;br /&gt;
raw_average -&amp;gt; Simpler Mittelwert ohne Berücksichtigung der Gewichtungen (ignores werden auch hier ignoriert)&lt;br /&gt;
&lt;br /&gt;
valve_average -&amp;gt; Mittelwert nach oben beschriebener Berechnung&lt;br /&gt;
&lt;br /&gt;
valve_max -&amp;gt; Größte aktuelle Ventilöffnung seit letztem Reset&lt;br /&gt;
&lt;br /&gt;
valve_min -&amp;gt; Kleinste aktuelle Ventilöffnung seit letztem Reset&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* {{Link2Forum|Topic=24658|Message=177528}} Thread im Forum, in dem dieses Modul vorgestellt wurde&lt;br /&gt;
* to be continued&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Regelungstechnik]]&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Heizungssteuerung]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=TelegramBot&amp;diff=34486</id>
		<title>TelegramBot</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=TelegramBot&amp;diff=34486"/>
		<updated>2020-12-28T20:24:37Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Fehlermeldungen bei veralteter SSL-Version */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Modul&lt;br /&gt;
|ModPurpose=Senden und Empfangen von Nachrichten (Text und Fotos) mit dem freien Messagingdienst Telegram&lt;br /&gt;
|ModType=d&lt;br /&gt;
|ModForumArea=Unterstützende Dienste&lt;br /&gt;
|ModFTopic=38328&lt;br /&gt;
|ModTechName=[https://github.com/viegener/Telegram-fhem/blob/master/50_TelegramBot.pm 50_TelegramBot.pm]&lt;br /&gt;
|ModOwner=[[Benutzer:Viegener|Viegener]] ({{Link2FU|12772|Forum}} / [[Benutzer Diskussion:Viegener|Wiki]])}}&lt;br /&gt;
&lt;br /&gt;
Das [[TelegramBot]]-Modul ermöglicht das Senden und Empfangen von Nachrichten über den Telegram-instant messaging Dienst (https://telegram.org/).&lt;br /&gt;
Es entsteht eine Möglichkeit Benachrichtungen aus FHEM zu versenden, zum Beispiel Alarmmeldungen.&lt;br /&gt;
Ausserdem können auch Kommandos über Telegram an FHEM gesendet werden um Steuerungsbefehle in FHEM auszulösen.&lt;br /&gt;
&lt;br /&gt;
Das TelegramBot-Modul benötigt keine Zusatzsoftware auf dem FHEM-Server&amp;lt;ref&amp;gt;anders als die Vorläufer-Variante über das [[Telegram - old API method|Telegram-API]]&amp;lt;/ref&amp;gt;, sondern verwendet das [https://core.telegram.org/bots/api TelegramBot-API] über https-Aufrufe. Es muss jedoch das [http://www.fhemwiki.de/wiki/Raspberry_Pi#N.C3.BCtzliche_Zusatzpakete perl JSON modul] installiert sein.&lt;br /&gt;
&lt;br /&gt;
== Über Telegram Instant Messaging ==&lt;br /&gt;
Telegram-IDs und Versand/Empfang von Nachrichten sind kostenfrei.&lt;br /&gt;
Clients sind für gängige Smartphonesysteme erhältlich (iOS iPhone und Tablet, Android, Windows Phone) und&lt;br /&gt;
können auch aus dem WebBrowser verwendet werden.&lt;br /&gt;
Es gibt auch einen Kommandozeilen-Client für Linux, der die Grundlage dieses Moduls darstellt.&lt;br /&gt;
Mehrfachanmeldungen, auch parallel mit verschiedenen Geräten (z.B. Tablet und Smartphone), sind möglich.&lt;br /&gt;
Gruppenchats und Chats mit End-2-End-Verschlüsselung werden ebenfalls unterstützt.&lt;br /&gt;
&lt;br /&gt;
Für die Unterstützung von &#039;&#039;WhatsApp&#039;&#039; siehe Modul [[yowsup]].&lt;br /&gt;
&lt;br /&gt;
Unterstützt werden:&lt;br /&gt;
&lt;br /&gt;
* Versand von Textnachrichten&lt;br /&gt;
* Versand und Empfang von Bildern/Audio/etc&lt;br /&gt;
* Empfang von Textnachrichten von beliebigen Kontakten&lt;br /&gt;
* Kommandos in FHEM über Telegram-Nachrichten von aussen auslösen&lt;br /&gt;
* Ergebnisse der Kommandos zusenden lassen&lt;br /&gt;
&lt;br /&gt;
Eine detaillierte Beschreibung des Moduls ist im FHEM Forum und in der (englischen) Dokumentation zum Modul in der {{Link2CmdRef|Anker=TelegramBot}} und in diesem  {{Link2Forum|Topic=38328|LinkText=Diskussionsthread}} zu finden. Seit Oktober 2015 wird das Modul offiziell über FHEM-Update verteilt.&lt;br /&gt;
&lt;br /&gt;
Die jeweils aktuellste Entwicklungs-Version des Moduls ist in Github [https://github.com/viegener/Telegram-fhem/blob/master/50_TelegramBot.pm 50_TelegramBot.pm] verfügbar.&lt;br /&gt;
&lt;br /&gt;
== TelegramBot Devices in FHEM ==&lt;br /&gt;
=== Define ===&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=Achtung: Dieses Authtoken ist die einzige Authentifizierung für den Bot und sollte deshalb nicht aus der Hand gegeben werden. Die verwendeten Urls sind deshalb auch in den Log-Files nicht enthalten, da diese das Authtoken in Klartext enthalten. Auch im Forum sollte dieses Token nicht aufgenommen werden.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Für die Anlage eines TelegramBot Devices in FHEM ist ein Authtoken erforderlich. Dieses Token wird über Anlegen eines neuen Bots im [https://core.telegram.org/bots#6-botfather BotFather] erzeugt (siehe dazu unten). Dafür muss der BotFather mit einem Telegram-Client kontaktiert werden. Dort mit dem Telegram-Befehl &amp;lt;code&amp;gt;/newbot&amp;lt;/code&amp;gt; einen neuen Bot anlegen und mit einem Namen versehen. Hinweis: Die Namen für Bots müssen auf &amp;quot;Bot&amp;quot; enden.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Anlegen eines TelegramBot devices erfolgt durch die Angabe dieses Tokens:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;define &amp;amp;lt;name&amp;amp;gt; TelegramBot  &amp;amp;lt;token&amp;amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel: &amp;lt;code&amp;gt;define myTelegramBot TelegramBot 110201543:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Das Empfangen von Nachrichten (polling) erfordert die Einstellung des Attributes&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code&amp;gt;pollingTimeout&amp;lt;/code&amp;gt; &#039;&#039;&#039;auf einen Wert der grösser als Null ist. Beim Wert 0 oder ohne Setzen des Attributes findet kein Polling und damit auch kein Empfang statt.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Beispiel: &amp;lt;code&amp;gt;attr myTelegramBot pollingTimeout 120&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Der TelegramBot kann erst dann Nachrichten an einen telegram user schicken, wenn dieser zuerst an den telegram bot eine Nachricht gesendet hat.&#039;&#039;&#039;&lt;br /&gt;
Dafür muss man in seinem Telegram-Client den Kontakt @botName suchen und dann eine Nachricht daran versenden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Der TelegramBot kann keine Nachrichten an andere Bots senden. Ein anderer Bot erhält die Nachrichten auch nicht wenn er in einer Gruppe enthalten ist.&#039;&#039;&#039; Dies ist eine Beschränkung in der Bot-Funktion bei Telegram. Das Versenden an einen anderen Bot (wenn man den Kontakt manuell hinzugefügt hat) führt zur Fehlermeldung&lt;br /&gt;
&amp;lt;code&amp;gt;sentMsgResult - Callback returned error :Bad Request: chat not found:&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=TelegramBot setzt eine aktuelle Version von FHEM voraus, insbesondere Versionen weit vor der Umstellung auf 5.7 (also vor Herbst 2015) können mit einem TelegramBot-Modul nicht funktionieren, da insbesondere das HTTPSRV-Modul dann veraltet ist. Am besten auch den TelegramBot über den offiziellen Update mit dem Rest von FHEM installieren/aktualisieren.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Registrierung eines neuen Bot ===&lt;br /&gt;
Zur Registrierung wird ein funktionierender Telegram-Client (egal ob Web, App oder Programm)benötigt. Hier wird ein Chat zum BotFather gestartet und der Befehl /newbot gesendet. Nun fragt der BotFather die benötigten Angaben ab und liefert am Ende des Dialogs die Informationen für den neuen Bot.&lt;br /&gt;
Hier ein Beispiel, wie so ein Chat aussehen könnte:&lt;br /&gt;
&amp;lt;pre&amp;gt;Client:&lt;br /&gt;
/newbot&lt;br /&gt;
----------------&lt;br /&gt;
BotFather:&lt;br /&gt;
Alright, a new bot. How are we going to call it? Please choose a name for your bot.&lt;br /&gt;
----------------&lt;br /&gt;
Client:&lt;br /&gt;
Mein Name&lt;br /&gt;
----------------&lt;br /&gt;
BotFather:&lt;br /&gt;
Good. Now let&#039;s choose a username for your bot. It must end in `bot`. Like this, for example: TetrisBot or tetris_bot.&lt;br /&gt;
----------------&lt;br /&gt;
Client:&lt;br /&gt;
fhem_bot&lt;br /&gt;
----------------&lt;br /&gt;
BotFather:&lt;br /&gt;
Sorry, this username is already taken. Think of something different.&lt;br /&gt;
----------------&lt;br /&gt;
Client:&lt;br /&gt;
fhem1234_bot&lt;br /&gt;
----------------&lt;br /&gt;
BotFather:&lt;br /&gt;
Done! Congratulations on your new bot.&lt;br /&gt;
You will find it at telegram.me/fhem1234_bot.&lt;br /&gt;
You can now add a description, about section and profile picture for your bot, see /help for a list of commands.&lt;br /&gt;
----------------&lt;br /&gt;
Use this token to access the HTTP API:&lt;br /&gt;
1234567890:AbCdefgHIJklmnOPQRst-uvwxyz&lt;br /&gt;
&lt;br /&gt;
For a description of the Bot API, see this page: https://core.telegram.org/bots/api&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=Achtung: Da Bots generell für alle Benutzer sichtbar sind und es gelegentlich Problem mit spammern gibt, die fremde bots auch in Gruppen hinzufügen, ist es empfehlenswert die Einstellung /setjoingroups auf false zu setzen, wenn die Zugehörigkeit zu Gruppen (und der Empfang von Meldungen aus gruppen) nicht notwendig ist&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen Chat an einen &amp;quot;Contact&amp;quot; versenden zu können, muss zuerst in Contacts (bei Readings) ein Kontakt auftauchen. Wenn man sich zum allerersten Mal bei Telegram angemeldet hat, gibt es noch keinen Chat mit irgendjemanden. Man muss sich zuerstmal selbst eine Nachricht im Smartphone zusenden, dann taucht unter Readings der Eintrag Contacts auf. Erst dann kann man eine Nachricht mit @msgPeerId (das ist Ziffernfolge des Contacts ) oder mit @msgPeer (das ist der Name nach dem Doppelpunkt) vom TelegramBot auf sein Smartphone senden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
&lt;br /&gt;
=== Privacyeinstellungen ===&lt;br /&gt;
&lt;br /&gt;
Damit der TelegramBot auch Meldungen in Gruppen sieht, müssen über den BotFather die Privacy-Einstellungen geändert werden.&amp;lt;br&amp;gt;Beispielchat:&amp;lt;pre&amp;gt;Client:&lt;br /&gt;
/setprivacy&lt;br /&gt;
----------------&lt;br /&gt;
BotFather:&lt;br /&gt;
Choose a bot to change group messages settings.&lt;br /&gt;
----------------&lt;br /&gt;
Client:&lt;br /&gt;
@fhem1234_bot&lt;br /&gt;
----------------&lt;br /&gt;
BotFather:&lt;br /&gt;
&#039;Enable&#039; - your bot will only receive messages that either start with the &#039;/&#039; symbol or mention the bot by username.&lt;br /&gt;
&#039;Disable&#039; - your bot will receive all messages that people send to groups.&lt;br /&gt;
Current status is: ENABLED&lt;br /&gt;
----------------&lt;br /&gt;
Client:&lt;br /&gt;
Disable&lt;br /&gt;
----------------&lt;br /&gt;
BotFather:&lt;br /&gt;
Success! The new status is: DISABLED. /help&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Siehe auch Info zu /setjoingroups oben.&lt;br /&gt;
&lt;br /&gt;
=== Kontakte ===&lt;br /&gt;
&lt;br /&gt;
Der Bot merkt sich die bereits bekannten Kontakte im Reading &amp;lt;code&amp;gt;Contacts&amp;lt;/code&amp;gt;. Dabei werden die einzelnen Kontakte jeweils als 3-teilige Einträge gespeichert - bestehend aus UserID, Vor- und Nachname des Benutzers (mit _ verbunden) und dem Username (mit vorangestelltem @).&lt;br /&gt;
&lt;br /&gt;
Beispiel: &amp;lt;code&amp;gt;123456:Ralf_Mustermann:@ralf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verschiedene Einträge werden durch Leerzeichen getrennt.&lt;br /&gt;
&lt;br /&gt;
Man kann die Kontakte auch manuell überschreiben (z.B. wenn das Reading fehlerhaft oder verloren sein sollte). Dazu gibt es den Set-Befehl &amp;lt;code&amp;gt;replaceContacts&amp;lt;/code&amp;gt;. Dieser nimmt die Kontakte ebenfalls in der gleichen Form wie oben beschrieben entgegen.&lt;br /&gt;
&lt;br /&gt;
Die Kontaktliste wird ansonsten nur durch den Empfang von Nachrichten erweitert, da es im TelegramBot-API keine Möglichkeit gibt Kontaktdaten von Telegram abzufragen (siehe auch pollingTimeout)&lt;br /&gt;
&lt;br /&gt;
=== Reset ===&lt;br /&gt;
&lt;br /&gt;
Es ist möglich den Bot im laufenden Betrieb zurückzusetzen (Set-Befehl &amp;lt;code&amp;gt;reset&amp;lt;/code&amp;gt;). Dabei werden noch nicht abgeschlossene Übetragungen entfernt und die internen Zustände des Devices zurückgesetzt.&lt;br /&gt;
&lt;br /&gt;
=== Gruppen ===&lt;br /&gt;
&lt;br /&gt;
Um eine Nachricht von FHEM an eine Gruppe zu senden, muss der BOT in die Gruppe aufgenommen werden. Nach dem Senden einer Nachricht an die Gruppe kann im Modul die Gruppen-ID ermittelt werden und zum Senden von Nachrichten verwendet werden. Die Gruppen-ID ist eine negative Zahl. Wenn die Privacy-Einstellungen nicht auf &#039;Disabled&#039; gesetzt wurden, muss die Nachricht mit einem Slash (/) beginnen.&lt;br /&gt;
&lt;br /&gt;
==== Supergroups / Supergruppen ====&lt;br /&gt;
&lt;br /&gt;
Auch die neuen Supergruppen werden mit dem Bot unterstützt, es ist allerdings zu beachten, dass bei der Umwandlung einer Gruppe in eine Supergruppe eine neue ID in den Kontakten von Telegram vergeben wird. Wenn man also wie empfohlen IDs zur Identifikation von Benutzern einsetzt, muss entsprechend angepasst werden.&lt;br /&gt;
&lt;br /&gt;
==== Fehlermeldungen bei veralteter SSL-Version ====&lt;br /&gt;
Telegram nutzt seit Februar 2020 eine neue Verschlüsselung und dies ruft bei veralteter Installation eine Fehlermeldung hervor:&lt;br /&gt;
&lt;br /&gt;
 NonBlockingGet: returned &amp;lt;hidden&amp;gt;: Can&#039;t connect(2) to &amp;lt;nowiki&amp;gt;https://api.telegram.org:443&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies deutet auf eine veraltete SSL-Version hin, siehe dazu die Forumsdiskussion ab {{Link2Forum|Topic=38328|Message=1021642|LinkText=diesem Beitrag}}. Hilfreich hat sich ein upgrade der SSL-Module erwiesen. Zuerst muss u.U. ein Modul installiert werden&lt;br /&gt;
:&amp;lt;code&amp;gt;sudo apt-get install libssl-dev&amp;lt;/code&amp;gt;&lt;br /&gt;
und danach in zwei Schritten&lt;br /&gt;
 sudo cpan &amp;lt;enter&amp;gt;&lt;br /&gt;
 upgrade net::SSLeay&amp;lt;enter&amp;gt;&lt;br /&gt;
Es ist bei Jessie zwingend ein Upgrade von &lt;br /&gt;
 IO::Socket::SSL 2.002 -&amp;gt; 2.066 &lt;br /&gt;
notwendig. Es wird darauf hingewiesen, dass idealerweise nicht einzelne Module, sondern das gesamte OS sowie alle Perlmodule auf den neuesten Stand gebracht werden sollten.&lt;br /&gt;
&lt;br /&gt;
=== Befehle von Telegram an FHEM senden ===&lt;br /&gt;
Es handelt sich hier um ein Tool, das {{Link2Forum|Topic=51425|Message=464928|LinkText=hier im Forum}} vorgestellt wurde. Dabei wird ein notify in FHEM angelegt, das den TelegramBot überwacht. Wird eine Befehlsfolge an den Bot gesendet, liest das Telegram-Device die gesendete Information aus und führt den Befehl aus. Weitere Details, wie hier vorzugehen ist, unter dem oben angegebenen Link im Forum.&lt;br /&gt;
&lt;br /&gt;
Wenn man an FHEM Befehle senden will, muss der TelegramBot bereit sein, diese Nachrichten zu empfangen. Wenn man allerdings aus Sicherheitsgründen das Attribut&lt;br /&gt;
:&amp;lt;code&amp;gt;allowUnknownContacts = 0&amp;lt;/code&amp;gt;&lt;br /&gt;
gesetzt hat, dann ist ein solcher Empfang nicht möglich. Daher muss (zumindest einmalig) erlaubt werden, von unbekannten Kontakten eine Nachricht zu bekommen. Nach dem ersten Empfang ist dann der Kontakt bekannt und man kann erneut den Empfang auf bekannte Kontakte beschränken.&lt;br /&gt;
&lt;br /&gt;
== Beispielszenarien ==&lt;br /&gt;
=== Benachrichtigungen über Ereignisse ===&lt;br /&gt;
Das einfachste Szenario für die Integration von Messaging-Diensten mit FHEM ist zur Benachrichtigung über Ereignisse. Diese Funktion kann zum Beispiel verwendet werden, um über einen erfolgten Neustart von FHEM zu informieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;define notify_fhem_reload notify global:INITIALIZED set myTelegramBot message fhem newly started - just now !&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird der Nachrichtentext &amp;quot;fhem newly started - just now !&amp;quot; an den als default eingestellten Kontakt (Attribut: defaultPeer) gesendet, sobald FHEM neu gestartet wurde. Natürlich kann man auch beliebige andere Benachrichtigungen einführen.&lt;br /&gt;
&lt;br /&gt;
Nebenbemerkung: hier ist eine erweiterte Strukturierung evt. empfehlenswert: statt jede Notify-Syntax o.ä. direkt auf TelegramBot-Spezifika gehen zu lassen, kann man sich eine Helper-Funktion (zur Vermittlung all solcher &amp;quot;Alarmtexte&amp;quot;) bauen ([[99_myUtils_anlegen]]), die entsprechende Alarm-Meldungen dann nur intern auf (u.a.) einen Messaging-Service wie (momentan!) Telegram schickt.&lt;br /&gt;
&lt;br /&gt;
=== Versand von Bildern ===&lt;br /&gt;
&lt;br /&gt;
Es ist auch möglich Bilder auf dem FHEM-Server, die zum Beispiel von einer Kamera oder einem Wettermodul stammen über Telegram zu versenden. So wäre es z.B. möglich jeweils morgens die aktuelle Wetterkarte zu erhalten.&lt;br /&gt;
&lt;br /&gt;
ACHTUNG: TelegramBot verwendet das HTTPUtils-Modul zur Kommunikation mit dem TelegramBot-API. Erst mit der Version, die seit 22.10.2015&lt;br /&gt;
([r9576] HttpUtils.pm: Async write for POST Requests {{Link2Forum|Topic=41583|LinkText=FHEM-Forum}}) verteilt wird, erlaubt auch den Transfer grösserer Bilder. Die Grenze liegt ansonsten bei ca. 14kb auf Raspberries (Plattformspezifische Grenze).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;define notify_fhem_reload notify wetter:report set myTelegramBot sendImage /opt/fhem/wetter.jpg&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei Erreichen des entsprechenden Status am Wetter-Modul wird ein Image über Telegram versendet. Hier sind lokale Pfade (relativ zu fhem) oder absolute Pfade wie oben möglich.&lt;br /&gt;
&lt;br /&gt;
=== Versand von SVG-Plots ===&lt;br /&gt;
&lt;br /&gt;
SVG-Plots können mit dem Befehl&lt;br /&gt;
&amp;lt;code&amp;gt;cmdSend [ @&amp;lt;peer1&amp;gt; ... @&amp;lt;peerN&amp;gt; ] &amp;lt;fhem command&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
verschickt werden.&lt;br /&gt;
&lt;br /&gt;
Das angegebene FHEM-Kommando wird ausgeführt und das Ergebnis an die angegebenen Peers bzw. den Standard-Peer verschickt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Befehl wird der SVG-Plot SVG_FileLog_Aussen an den Standard-Peer geschickt:&lt;br /&gt;
&amp;lt;code&amp;gt;set myTelegramBot cmdSend { plotAsPng(&#039;SVG_FileLog_Aussen&#039;) }&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nach &amp;lt;code&amp;gt;define cmd_sendTelegramSVG cmdalias TGSVG .* AS set myTelegramBot cmdSend { plotAsPng(&amp;quot;$EVENT&amp;quot;) }&amp;lt;/code&amp;gt;&lt;br /&gt;
kann man mit einem kurzen&lt;br /&gt;
&amp;lt;code&amp;gt;TGSVG SVG_Garten&amp;lt;/code&amp;gt;&lt;br /&gt;
ein beliebiges SVG über die Kommandozeile per Telegram versenden.&lt;br /&gt;
&lt;br /&gt;
Um das SVG nun noch mit einem Text zu versehen, muss eine Textnachricht dazu gesendet werden, was sich am einfachsten durch das Ausführen eines FHEM-Befehls auf Perl-Ebene realisieren lässt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;{fhem &amp;quot;set myTelegramBot message Bildbeschreibung;; set myTelegramBot cmdSend { plotAsPng(&#039;mein_SVG&#039;) }&amp;quot; }&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; früher wurde zum Verschicken von Plots auch die interne Funktion TelegramBot_ExecuteCommand verwendet; mit dem Update Ende Februar 2017 hat diese Funktion einen zusätzlichen Parameter erhalten und lautet nun&lt;br /&gt;
&amp;lt;code&amp;gt;TelegramBot_ExecuteCommand($defs{&amp;quot;myTelegramBot&amp;quot;}, meine_ZielID, undef, &#039;{plotAsPng(&amp;quot;mein_SVG&amp;quot;)}&#039;);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Voraussetzungen für den Versand von SVG-Plots ====&lt;br /&gt;
Es muss das Modul libimage-librsvg-perl installiert sein:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sudo apt-get install libimage-librsvg-perl&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Evtl. sind weitere Module erforderlich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sudo apt-get install libgd-graph-perl&lt;br /&gt;
&lt;br /&gt;
sudo apt-get install libgd-text-perl&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Empfang von Bildern oder ähnlichem ===&lt;br /&gt;
&lt;br /&gt;
Beim Empfang von Bildern wird zuerst nur eine ID vom Telegram-Server empfangen, diese befindet sich im Reading &amp;lt;code&amp;gt;msgFileId&amp;lt;/code&amp;gt; angelegt (&amp;lt;code&amp;gt;123456:xxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxx&amp;lt;/code&amp;gt;) und im Reading &amp;lt;code&amp;gt;msgText&amp;lt;/code&amp;gt; steht dann so etwas wie&lt;br /&gt;
&amp;lt;code&amp;gt;received photo # Size: 107701&amp;lt;/code&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
Über das Get-Kommando &amp;lt;code&amp;gt;urlForFile&amp;lt;/code&amp;gt; mit der ID aus dem msgFileId Reading lässt sich dann daraus ein URL ableiten, der dann zur eigentlichen Datei führt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;https://api.telegram.org/file/bot123456:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/photo/file_25.jpg&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Versand von Emojis (Smileys) ===&lt;br /&gt;
&lt;br /&gt;
Es ist auch möglich Emojis mit den (Text-)Nachrichten zu versenden. Die entsprechenden (Unicode-)Zeichen werden einfach direkt mit in den Text der Nachricht aufgenommen. Um das zu vereinfachen kann man das einfach per Copy und Paste von dieser Seite&lt;br /&gt;
&lt;br /&gt;
http://apps.timwhitlock.info/emoji/tables/unicode (Spalte &amp;quot;Native&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
übernehmen und mit der Nachricht verschicken.&lt;br /&gt;
&lt;br /&gt;
Die Emojis können auch empfangen werden und werden so auch in FHEM / FHEMWeb angezeigt. Plattformspezifische (z.B. von iOS oder Android) Emojis werden dabei nicht unterstützt (gerade mit iOS sind viele neue farbige Emojis hinzugekommen, die wohl leider nur auf Apple-devices funktionieren).&lt;br /&gt;
&lt;br /&gt;
=== Kommandos auslösen ===&lt;br /&gt;
&lt;br /&gt;
Ein wichtiges Szenario ist die Möglichkeit Kommandos in FHEM ausführen zu können, ohne einen Zugang durch die Firewall einrichten zu müssen. Dazu ist die Definition eines Schlüsselwortes (Attribut: &amp;quot;cmdKeyword&amp;quot;) erforderlich, mit dem man die Nachrichten beginnen muss, damit der TelegramBot die Kommandos erkennt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;attr myTelegramBot cmdKeyword doit&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Somit kann man dann durch Nachrichten die mit &amp;quot;doit&amp;quot; beginnen Kommandos an FHEM senden, die ähnlich wie im Kommandoeingabefeld von FHEMweb dann von FHEM ausgeführt werden. Das Ergebnis der Ausführung wird zurück an den Sender (und an den definierten defaultPeer) geschickt.&lt;br /&gt;
&lt;br /&gt;
Somit können nicht nur Aktionen angestossen werden, sondern auch Infos abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiele&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;doit set schalter on&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;doit list telegrambot&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== TelegramBot-Aktionen auslösen ====&lt;br /&gt;
Der Bot sendet Nachrichten standardmäßig an den defaultPeer (falls definiert). So kann mit folgendem Befehl etwa der Versand eines Videos ausgelöst werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;doit set telegrambot sendMedia cam.mp4&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soll eine Nachricht an einen anderen (bekannten) User geschickt werden, so ist die Angabe der ID des Users erforderlich. Dies kann dynamisch mit set-Logik und Abfrage der Readings erfolgen. Der folgende Befehl sendet das Video an den User, der das Kommando an den Bot geschickt hat:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;doit set telegrambot sendMedia @[TB:msgChatId] cam.mp4&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei der Definition von Favoriten (siehe unten) kann genau so vorgegangen werden.{{Randnotiz|RNTyp=Warn|RNText=Achtung: Bei den Kommandos sollten man unbedingt das Attribut &amp;quot;cmdRestrictedPeer&amp;quot; setzen, damit nicht jeder Kommandos auf dem FHEM-Server ausführen kann. Dazu sollten die BenutzerIDs der erlaubten Benutzer (durch Leerzeichen getrennt angeben). Da Benutzernamen selber vergeben werden und nicht unbedingt eindeutig sind, sollten hier auch NUR BenutzerIDs verwendet werden.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==== Favoriten für Kommandos anlegen ====&lt;br /&gt;
Grundidee bei den Favoriten ist, dass man lange Befehle, die man häufig braucht auf &amp;quot;Kurzwahl&amp;quot; legt.&lt;br /&gt;
&lt;br /&gt;
Beispiel-Kommandos wie z.B. &amp;lt;code&amp;gt;set TYPE=ROLLLADEN pos 100&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;set TYPE=ROLLLADEN pos 0&amp;lt;/code&amp;gt;, die man immer wieder braucht. Um nicht jedes mal dieses Kommando eintippen zu müssen auf dem Smartphone, kann man auch dafür Favoriten anlegen.&lt;br /&gt;
&lt;br /&gt;
Dazu gibt man erst mal die beiden Kommandos getrennt durch Semikolon im Attribut favorites an:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;attr myTelegramBot favorites set TYPE=ROLLLADEN pos 100;set TYPE=ROLLLADEN pos 0&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um die Favorites jetzt ausführen zu können braucht man noch ein Schlüsselwort dafür.&lt;br /&gt;
Nehmen wir mal an man möchte die Favoriten mit &amp;lt;code&amp;gt;/short&amp;lt;/code&amp;gt; ausführen können. Dazu muss dann das Attribut &amp;quot;cmdFavorites&amp;quot; setzen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;attr myTelegramBot cmdFavorites /short&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn man nun im Telegram Client&lt;br /&gt;
&amp;lt;code&amp;gt;/short 1&amp;lt;/code&amp;gt; an den Bot schickt führt der Bot den ersten Favoriten aus und das Ergebnis der Ausführung wird zurückgeschickt.&lt;br /&gt;
&lt;br /&gt;
Ausserdem kann man im Telegram Client&lt;br /&gt;
&amp;lt;code&amp;gt;/short&amp;lt;/code&amp;gt; an den Bot schicken, dann antwortet der Bot mit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Favorites&lt;br /&gt;
&lt;br /&gt;
/short1 = set TYPE=ROLLLADEN pos 100&lt;br /&gt;
&lt;br /&gt;
/short2 = set TYPE=ROLLLADEN pos 0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Antworten werden als Schaltflächen dargestellt (Telegram inline Keyboard) und können am Mobile-Client direkt angeklickt werden um sie auszuführen.&lt;br /&gt;
Um die Beschriftung der Schaltflächen zu optimieren, können die Befehle im Attribut favorites mit Beschreibungen versehen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/[Rolllaeden zu ]=set TYPE=ROLLLADEN pos 100;/[Rolllaeden auf]=set TYPE=ROLLLADEN pos 0&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun antwortet der Bot auf das Schlüsselwort für die Favoriten mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Favorites&lt;br /&gt;
&lt;br /&gt;
/short1 = Rolllaeden zu&lt;br /&gt;
&lt;br /&gt;
/short2 = Rolllaeden auf&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Nützliche Kombinationen mit weiteren Modulen ===&lt;br /&gt;
&lt;br /&gt;
==== msgConfig ====&lt;br /&gt;
{{Link2CmdRef|Anker=msgConfig|Lang=de|Label=msgConfig}}&lt;br /&gt;
&lt;br /&gt;
{{Link2CmdRef|Anker=msgDialog|Lang=de|Label=msgDialog}}&lt;br /&gt;
&lt;br /&gt;
==== msgDialog ====&lt;br /&gt;
[[MsgDialog]]&lt;br /&gt;
&lt;br /&gt;
==== MSG ====&lt;br /&gt;
[[Msg]]&lt;br /&gt;
&lt;br /&gt;
{{Link2CmdRef|Anker=MSG|Lang=en|Label=MSG}}&lt;br /&gt;
&lt;br /&gt;
{{Link2Forum|Topic=39983|LinkText=Forum-Beitrag}}&lt;br /&gt;
&lt;br /&gt;
==== PostMe ====&lt;br /&gt;
[[Modul PostMe#Steuerung per Telegram|PostMe]]&lt;br /&gt;
&lt;br /&gt;
{{Link2CmdRef|Anker=PostMe|Lang=de|Label=PostMe}}&lt;br /&gt;
&lt;br /&gt;
{{Link2CmdRef|Anker=TBot_List|Lang=en|Label=TBot_List}}&lt;br /&gt;
&lt;br /&gt;
==== ROOMATE ====&lt;br /&gt;
{{Link2CmdRef|Anker=ROOMMATE|Lang=de|Label=ROOMMATE}}&lt;br /&gt;
&lt;br /&gt;
==== MAX ====&lt;br /&gt;
[[MAX#Telegram-Benachrichtigung bei dauergeöffnetem Fenster|Dauer-offenes Fenster melden]]&lt;br /&gt;
&lt;br /&gt;
==== SSCAM - Steuerung von Kameras in Synology Surveillance Station - Schnappschüsse mit TelegramBot versenden ====&lt;br /&gt;
[[SSCAM - Steuerung von Kameras in Synology Surveillance Station#Schnappschüsse mit TelegramBot versenden|Schnappschüsse mit TelegramBot versenden]]&lt;br /&gt;
&lt;br /&gt;
==== PRESENCE ====&lt;br /&gt;
[[PRESENCE#Hinweis zur Benutzung / Fehlerhandling|Hinweis zur Benutzung / Fehlerhandling]]&lt;br /&gt;
&lt;br /&gt;
==== AMAD ====&lt;br /&gt;
[[AMAD]]&lt;br /&gt;
&lt;br /&gt;
==== TALKTOME &amp;amp; TALKTOUSER ====&lt;br /&gt;
[[TALKTOME &amp;amp; TALKTOUSER - Sprachverarbeitung für Nutzerinteraktionen#Beleuchtungssteuerung mit Telegram|Beleuchtungssteuerung mit Telegram]]&lt;br /&gt;
&lt;br /&gt;
==== Staumelder ====&lt;br /&gt;
[[Staumelder#telegram|Staumelder]]&lt;br /&gt;
&lt;br /&gt;
==== Grafana ====&lt;br /&gt;
[[Grafana#Speichern und Senden von Grafiken (zB_mit_Telegram)|Grafana-Plots versenden]]&lt;br /&gt;
&lt;br /&gt;
==== Talk2Fhem ====&lt;br /&gt;
[[Talk2Fhem#Messenger Telegram|Talk2Fhem]]&lt;br /&gt;
&lt;br /&gt;
==== Hausüberwachung ====&lt;br /&gt;
[[Hausüberwachung#Nachrichten aus dem Haus|Nachrichten aus dem Haus]]&lt;br /&gt;
&lt;br /&gt;
==== Gäste-WLAN der Fritzbox auswerten und Login per Telegram senden ====&lt;br /&gt;
&lt;br /&gt;
{{Link2Forum|Topic=100119|Message=936495|LinkText=Forum-Beitrag}}&lt;br /&gt;
&lt;br /&gt;
==== Batterieüberwachung nur einmal täglich ====&lt;br /&gt;
{{Link2Forum|Topic=99219|Message=926652|LinkText=Forum-Beitrag}}&lt;br /&gt;
&lt;br /&gt;
==== BOTVAC ====&lt;br /&gt;
[[BOTVAC#MAPS|Saugroboter-Karten]]&lt;br /&gt;
&lt;br /&gt;
==== Unifi Voucher bereistellen über msgDialog ====&lt;br /&gt;
[[Unifi#über Telegram|Unifi Voucher]]&lt;br /&gt;
&lt;br /&gt;
[[Unifi#Erkennung neuer clients|Erkennung unbekannter Clients]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Github Repository für die Telegram-FHEM Entwicklung: https://github.com/viegener/Telegram-fhem&lt;br /&gt;
* Infos zum Telegram BotFather: https://core.telegram.org/bots#6-botfather&lt;br /&gt;
&lt;br /&gt;
* Source code für das 50_TelegramBot.pm-Modul: https://github.com/viegener/Telegram-fhem/blob/master/50_TelegramBot.pm&lt;br /&gt;
&lt;br /&gt;
* Forum-Thread in dem das Modul vorgestellt wurde {{Link2Forum|Topic=38328|LinkText=FHEM-Forum}}&lt;br /&gt;
* Telegram messaging system https://telegram.org/&lt;br /&gt;
* TelegramBot API https://core.telegram.org/bots/api&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
[[Kategorie:Telegram]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=33973</id>
		<title>MSwitch</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=33973"/>
		<updated>2020-10-04T18:40:35Z</updated>

		<summary type="html">&lt;p&gt;Maista: Aktuelle Modulversion 4.1&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{Hinweis|Das Modul wurde vom Modulautor aus dem FHEM-SVN entfernt. Download des Moduls unter https://github.com/Byte009/Fhem-MSwitch. Support erfolgt laut github-Seite derzeit über Whatsapp.}}&lt;br /&gt;
&lt;br /&gt;
Achtung: Das Wiki entspricht nicht mehr der aktuellen Modulversion ( V4.1 )&lt;br /&gt;
&lt;br /&gt;
Hilfe zu allen Befehlen , Einstellungen etc. ist direkt über das Frontend eines MSwitch-Devices verfügbar.&lt;br /&gt;
&lt;br /&gt;
Eine Aktualisierung des Wikis erfolgt in den kommenden Tagen.&lt;br /&gt;
&lt;br /&gt;
[[MSwitch]] ist ein Hilfsmodul, welches das Event- und/oder zeitgesteuerte Schalten von mehreren Devices oder das Ausführen von benutzerdefinierten Befehlssequenzen erlaubt. Hauptmerkmale sind die fast vollständige und die sehr umfangreiche Konfigurierbarkeit über das Webinterface.&lt;br /&gt;
&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=MSwitch&lt;br /&gt;
|ModType=x&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=98_MSwitch.pm&lt;br /&gt;
|ModOwner=Byte09 (aus dem Forum abgemeldet)}}&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz | RNTyp=y | RNText=Byte09: &#039;&#039;Die Grundidee zu MSwitch kam mir, weil ich bei der Arbeit mit FHEM für meinen Geschmack zu viele Module für die verschiedenen Aufgaben brauchte - zu allem Überfluss alle mit unterschiedlicher Syntax. Zwar ist DOIF hiervon ausgenommen (da hiermit wohl auch fast jede Aufgabe lösbar ist), aber ich konnte mich leider nicht daran gewöhnen und somit wurde jedes DOIF für mich zu einem echten Projekt. Was ich wollte war ein Modul, mit dem ich alles erledigen kann. Daher entschloss ich mich schon nach fast einem knappen Jahr FHEM-Nutzung mein eigenes Modul zu schreiben, welches diese Anforderung erfüllt. MSwitch beinhaltet die Funktionalität aller bisherigen Hilfsmodule wie z.B. Notify, Doif, Watchdog, Dummy,( ab Modulversion 2.2 auch Sequenz ) es lassen sich all deren Funktionen umsetzen.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;MSwitch wird permanent - vorrangig nach meinen Bedürfnissen - weiterentwickelt, gerne nehme ich aber auch Anregungen von anderen Nutzern auf.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Datei:1-2-3-4.png|rahmenlos]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Grundsätzliche Überlegungen ==&lt;br /&gt;
{{Randnotiz | RNTyp=y | RNText=Will man mehrere Geräte als gleichzeitige Auslöser betreiben, so muss das Device GLOBAL gewählt und die entsprechenden Geräte angegeben werden (dies erzeugt höhere Systemlast und ist nur im Expert-Modus verfügbar).}} &lt;br /&gt;
&lt;br /&gt;
1. Welches Gerät soll auslösen oder zu welcher Zeit soll eine Auslösung erfolgen? &lt;br /&gt;
[[Datei:MSwitch basic.svg|mini|240px|Stark vereinfachtes Struktogramm]]&lt;br /&gt;
Im Rahmen 1 des Webinterfaces lässt sich der Trigger (Auslöser) bzw. eine Zeitabhängigkeit konfigurieren:&lt;br /&gt;
&lt;br /&gt;
** jedes Event aus dem Eventmonitor,&lt;br /&gt;
** triggerunabhängige Zeiten, &lt;br /&gt;
** triggerunabhängige Zufallszeiten,&lt;br /&gt;
** triggerunabhängige Intervalle,&lt;br /&gt;
** Kombinationen aus Triggern und Zeiten.&lt;br /&gt;
&lt;br /&gt;
2. Welche Bedingungen sollen bei Auslösung erfüllt sein?&lt;br /&gt;
: Ersten Rahmen: Wenn diese Bedingungen erfüllt sind, werden Kommandos ausgelöst. Die Bedingungen werden im zweiten Teil des Webinterfaces eingegeben. Dabei unterscheidet das Modul zwischen zwei Kommando-Kanälen (cmd1 und cmd2) und den dazugehörigen Geräten.&lt;br /&gt;
&lt;br /&gt;
3. Welche Kommandos sollen ausgelöst werden?&lt;br /&gt;
: Im vierten Rahmen des Webinterfaces werden dann die konkreten Kommandos eingegeben. Man wählt dabei aus einer Liste wie auf der Geräteseite Kommandos aus. FreeCmd erlaubt geräteunabhängige Kommandos, beispielsweise reinen Perl-Code.&lt;br /&gt;
&lt;br /&gt;
4. Welche weiteren Bedingungen sollen noch gelten?&lt;br /&gt;
: Zusätzlich pro Gerät eine oder mehrere Instanzen des vierten Rahmens:&lt;br /&gt;
** ereignisgesteuerte Bedingungen,&lt;br /&gt;
** zeitgesteuerte Bedingungen,&lt;br /&gt;
** Verzögerungen,&lt;br /&gt;
** Wiederholungen etc.&lt;br /&gt;
&lt;br /&gt;
==Definition und Einrichtung =={{Randnotiz | RNTyp=y | RNText=Alle relevante Einstellungen werden in Readings und/oder Hashes gespeichert. Daher stehen relevanten Daten &#039;&#039;nicht&#039;&#039; in der fhem.cfg! Vielmehr finden sich diese Daten in der Datei fhem.save. Die Speicherung erfolgt durch den Befehl Fhemsave.&lt;br /&gt;
}}&lt;br /&gt;
Das MSwitch-Modul ist ohne weitere Voraussetzungen nutzbar und wird in der aktuellen Version über FHEM Update verteilt. MSwitch kann mehrere Devices gleichzeitig schalten. Diese Schaltungen befinden sich in den zwei möglichen Zweigen entsprechend der Kommandos cmd1 und cmd2. Die einzelnen Devices jedes Zweiges können mit weiteren Schaltbedingungen versehen werden (zeit- oder ereignisgesteuert). Das define eines MSwitch Devices generiert lediglich eine &#039;leere Hülle&#039;:&lt;br /&gt;
:&amp;lt;code&amp;gt;define &amp;lt;name&amp;gt; MSwitch&amp;lt;/code&amp;gt;&lt;br /&gt;
Es wird ein leeres Device angelegt, das dann komplett über das Webinterface konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
== Webinterface ==&lt;br /&gt;
MSwitch wird über das Webinterface eingerichtet. Es besteht aus vier Teilen. Änderungen in einem Abschnitt müssen auch dort gespeichert werden, bevor ein weiterer Teil bearbeitet wird, sonst gehen Änderungen verloren.{{Randnotiz | RNTyp=y | RNText=&amp;lt;code&amp;gt;attr &amp;lt;name&amp;gt; MSwitch_Help 1&amp;lt;/code&amp;gt; führt dazu, dass im Modul selber eine sehr umfangreiche kontextsensitive Hilfe in Form von Fragezeichensymbolen angezeigt wird.}} &lt;br /&gt;
&lt;br /&gt;
[[Datei:1-2-3-4.png|rahmenlos|Webinterface]]&lt;br /&gt;
=== Rahmen 1: Trigger Device und Trigger Time ===&lt;br /&gt;
==== Trigger Device ====&lt;br /&gt;
{{Randnotiz | RNTyp=y | RNText=Wenn das Attribut &#039;MSwitch_Expert&#039; gesetzt ist kann man &#039;GLOBAL&#039; auswählen. Dann werden &#039;&#039;&#039;alle&#039;&#039;&#039; von FHEM generierten Events durch das MSwitch Device weiterverarbeitet, eine weitere Begrenzung kann (und sollte) dann in einem folgenden Eingabefeld erfolgen, um die Systemlast zu reduzieren.&lt;br /&gt;
==== Trigger Device Global Whitelist ====&lt;br /&gt;
Damit kann die Liste eingehender Events weiter eingeschränkt werden. Sobald mindestens ein Eintrag vorhanden sind, werden nur noch Events der hier benannten Devices verarbeitet. Zulässig ind Devicenamen und DeviceTypen (z.B. TYPE=FS20). Mehrere Angaben sind durch Komma zu trennen.&lt;br /&gt;
&lt;br /&gt;
Im unten gezeigten Beispiel wurde GLOBAL gewählt, weil nicht ein einzelnes Device, sondern eine Kombination aus zwei Geräten auslösen soll. Es werden alle Ereignisse betrachtet, wobei die Whitelist dann auf die Devices Schlafzimmer (ein Temperaturmessgerät) und Schlafzimmerfenster (ein [[HM-Sec-SCo Tür-Fensterkontakt, optisch|optischer Kontakt]]) einschränkt.}}In diesem Feld wird das Device per Dropdownfeld gewählt, dessen Events eine Aktion auslösen sollen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:MSwitchWebinterface1.png|400px|thumb|right|Webinterface, oben]]&lt;br /&gt;
&lt;br /&gt;
==== Trigger Time ==== &lt;br /&gt;
Trigger time bietet die Möglichkeit einer zeitabhängigen Steuerung. Dazu wird in die &amp;quot;at&amp;quot;-Zeile ein Termin in der Form [STUNDEN:MINUTEN|TAGE] eingetragen. Die Tage werden ab Montag von 1-7 gezählt. Mehrere Zeitvorgaben können direkt hintereinander geschrieben werden. Beispiele:&lt;br /&gt;
* &amp;lt;code&amp;gt;[17:00|1][18:30|23]&amp;lt;/code&amp;gt; löst montags um 17 Uhr und dienstags sowie mittwochs um 18:30 Uhr aus.&lt;br /&gt;
* &amp;lt;code&amp;gt;[00:10*20:00-21:00]&amp;lt;/code&amp;gt; führt den Schaltbefehl von 20 Uhr bis 21 Uhr alle 10 Minuten aus.&lt;br /&gt;
* &amp;lt;code&amp;gt;[?20:00-21:00]&amp;lt;/code&amp;gt; schaltet zu einem zufälligen Zeitpunkt zwischen 20 und 21 Uhr einmalig.  &lt;br /&gt;
* &amp;lt;code&amp;gt;[20:00|$we]&amp;lt;/code&amp;gt; nur am Wochenende um 20:00 wird geschaltet.&lt;br /&gt;
&lt;br /&gt;
==== Trigger Conditions ====&lt;br /&gt;
&lt;br /&gt;
Optionale zusätzliche Bedingungen in diesem Feld gelten nur für auslösende Device Trigger. Trigger Times haben keinen Einfluss, es sei denn, das Attribut MSwitch_Condition_Time ist gesetzt. Man kann mit AND / OR verknüpfte Bedingungen für die Auslösung in an DOIF angelehnter Syntax angeben. Leere Felder werden ignoriert. Werden Readings mit Strings wie &#039;on&#039; oder &#039;off&#039; abgefragt, ist statt des Gleichheitszeichens &amp;quot;=&amp;quot; der Operator &amp;quot;eq&amp;quot; zu nutzen, der String muss in Anführungszeichen &amp;quot;&amp;quot; gesetzt werden. Beispiele:{{Randnotiz | RNTyp=y | RNText=Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (beispielsweise würde dann am Mittwoch noch der Schaltvorgang erfolgen, obwohl als Tagesvorgabe Dienstag gesetzt wurde).}} &lt;br /&gt;
* &amp;lt;code&amp;gt;[19:10-23:00] AND [Devicename:Reading] = 10&amp;lt;/code&amp;gt; beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
* &amp;lt;code&amp;gt;[19:10-23:00] OR [Devicename:Reading] eq &amp;quot;on&amp;quot;&amp;lt;/code&amp;gt; eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
* &amp;lt;code&amp;gt;[10:00-11:00|13]&amp;lt;/code&amp;gt; schaltet Montag und Mittwoch zwischen 10 Uhr und 11 Uhr.&lt;br /&gt;
* &amp;lt;code&amp;gt;[{ sunset() }-23:00]&amp;lt;/code&amp;gt; von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
* &amp;lt;code&amp;gt;{ !$we }&amp;lt;/code&amp;gt; löst den Schaltvorgang nur Werktagen an aus.&lt;br /&gt;
* &amp;lt;code&amp;gt;{ $we }&amp;lt;/code&amp;gt; löst den Schaltvorgang nur an Wochenenden, Feiertagen aus.&lt;br /&gt;
Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
=== Rahmen 2: Trigger Details ===&lt;br /&gt;
[[Datei:MSwitchWebinterface2.png|600px|thumb|right|Webinterface, Mitte]]&lt;br /&gt;
Der Inhalt des zweiten Rahmens wird mit dem gewählten Trigger aus dem ersten Rahmen initialisiert. Events können zugeordnet werden. Im Beispiel wird cmd1 ausgelöst, wenn das Fenster offen ist. Cmd2 wird bei Temperaturunterschreitung ausgelöst.&lt;br /&gt;
&lt;br /&gt;
==== execute ====&lt;br /&gt;
Diese vier Zeilen legen fest, welches ankommende Event welchen Befehlszweig auslösen soll. Die Event-Drop-Down-Liste enthält alle empfangenen Events dieses Devices. Fehlende Events können manuell hinzugefügt werden.&lt;br /&gt;
&lt;br /&gt;
* switch &amp;lt;MSwitch&amp;gt; on + execute &#039;cmd1&#039; -  MSwitch Statusänderung auf &#039;on&#039;; cmd1 soll ausgeführt werden&lt;br /&gt;
* switch &amp;lt;MSwitch&amp;gt; off + execute &#039;cmd2&#039; - MSwitch Statusänderung auf &#039;off&#039;; cmd2 soll ausgeführt werden; &lt;br /&gt;
* execute &#039;cmd1&#039; only - keine Statusänderung; cmd1 soll ausgeführt werden&lt;br /&gt;
* execute &#039;cmd2&#039; only - keine Statusänderung; cmd2 soll ausgeführt werden&lt;br /&gt;
&lt;br /&gt;
==== Save incomming events ====&lt;br /&gt;
Alle ankommenden Events der konfigurierten Geräte werden für die Dropdownlisten gespeichert. Nach erfolgreicher Konfiguration sollte diese Option entfernt werden, um die Datenmenge zu reduzieren. Falls das Device Events während der Konfiguration nicht liefert, können sie manuell als kommagetrennte Liste hinzugefügt werden.&lt;br /&gt;
&lt;br /&gt;
==== add event ====&lt;br /&gt;
{{Randnotiz | RNTyp=y | RNText=Falls auf &#039;GLOBALE&#039; Events getriggert wird, muss das auslösende Device vorangestellt werden:&lt;br /&gt;
- *                                                           - alle auftretende Events des entsprechenden Device&lt;br /&gt;
- device:reading:wert   (z.B. device:state:on )                      - nur für das Event &amp;quot;device:state:on&amp;quot;&lt;br /&gt;
- device:reading:*      (z.B. device:state:* )                       - Events &amp;quot;device:state:(on,off,etc.)&lt;br /&gt;
- device:reading:(wert1/wert2/wert3) (z.b. device:state:(left/right) - Events &amp;quot;device:state:left&amp;quot; oder &amp;quot;devicestate:right&amp;quot; etc.&lt;br /&gt;
&lt;br /&gt;
Das Device kann auch hier gegen &amp;quot;*&amp;quot; ersetzt werden (*:state:on). In diesem Fall erfolgt eine Aktion auf alle Events die z.B. &amp;quot;state:on&amp;quot; enthalten, egal welches Device triggert.&lt;br /&gt;
}} &lt;br /&gt;
* *                                                    - alle auftretende Events des entsprechenden Device&lt;br /&gt;
* reading:wert   (z.B. state:on )                      - nur auf das Event &amp;quot;state:on&amp;quot;&lt;br /&gt;
* reading:*      (z.B. state:* )                       - Events &amp;quot;state:(on,off,etc.)&lt;br /&gt;
* reading:(wert1/wert2/wert3) (z.b. state:(left/right) - Events &amp;quot;state:left&amp;quot; oder &amp;quot;state:right&amp;quot; etc.&lt;br /&gt;
==== test event ====&lt;br /&gt;
Stehen Events zur Auswahl, kann die Konfiguration getestet werden. Durch Klick wird das Event simuliert und die dafür definierte Aktion ausgelöst. &lt;br /&gt;
&lt;br /&gt;
==== apply filter to saved events ====&lt;br /&gt;
Beschreibung folgt???&lt;br /&gt;
&lt;br /&gt;
==== clear saved event ====&lt;br /&gt;
Es werden die nicht als Trigger wirkenden Events aus der Liste gelöscht.&lt;br /&gt;
&lt;br /&gt;
=== Rahmen 3: Affected devices ===&lt;br /&gt;
{{Randnotiz | RNTyp=y | RNText=In dem Auswahlfeld werden alle Devices angeboten, die eines der folgenden Kriterien erfüllen:&lt;br /&gt;
# Die Abfrage &amp;quot;set Device ?&amp;quot; liefert einen Befehlssatz&lt;br /&gt;
# Das Attribut &#039;webcmd&#039; des Devices enthält Einträge&lt;br /&gt;
# Das Attribut &#039;MSwitch_Activate_MSwitchcmds&#039; ist aktiviert und das Attribut &#039;MSwitchcmds&#039; des betreffenden Devices enthält einen Befehlssatz&lt;br /&gt;
&lt;br /&gt;
Einzige Ausnahme ist der erste Listeneintrag &#039;FreeCMD&#039;. Die Auswahl dieses Eintrages bietet später die Möglichkeit Befehle auszuführen, die nicht an ein Device gebunden sind. Der Code in einem FreeCmd kann entweder reiner FHEM-Code sein ( set device on ) oder reiner Perl-Code. Wenn es sich um reinen Perl-Code handelt, ist dieser in geschweifte Klammen zu setzen { Perl-Code }.&lt;br /&gt;
&lt;br /&gt;
}} &lt;br /&gt;
[[Datei:MSwitch_Screen_5.png|mini|rechts|affected devices]]&lt;br /&gt;
Auswahl der Devices, die auf die oben konfigurierten Events reagieren sollen. Um unbeabsichtigte Änderungen zu vermeiden ist die direkte Mehrfachauswahl gesperrt.&lt;br /&gt;
&lt;br /&gt;
=== Rahmen 4: Device Actions ===&lt;br /&gt;
&lt;br /&gt;
[[Datei:Webinterface3.png|mini|rechts|device_actions]]&lt;br /&gt;
Die auszuführenden Aktionen der im dritten Rahmen gewählten Geräte. Leere Felder werden ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== MSwitch cmd1/cmd2:  ====&lt;br /&gt;
{{Randnotiz | RNTyp=y | RNText=Im Beispiel befindet sich ein FreeCmd, mit dem beliebige Kommandos eingetragen werden können. Im abgebildeten Beispiel ist dies sogar selbst definierter Perl-Code (die Funktion DebianMail sendet eine Mail).&lt;br /&gt;
}} &lt;br /&gt;
Man wählt den gewünschten Befehl aus den gespeicherten verfügbaren Möglichkeiten des betreffenden Device aus. &lt;br /&gt;
&lt;br /&gt;
* Im Sonderfall FreeCmd wird der Befehl als String eingegeben. &lt;br /&gt;
* Das Attribut MSwitch_Extensions ergänzt die Schaltoption &#039;MSwitchToggle&#039; in der Liste, um die Toggle-Funktion bei Geräten die sie nicht von Haus aus anbieten nachzurüsten. &lt;br /&gt;
&lt;br /&gt;
{{Randnotiz | RNTyp=y | RNText=Je nach Attribut-Einstellungen werden Einträge aus entsprechenden &#039;webcmds&amp;quot; oder &#039;MSwitchcmds&#039; einbezogen. In Abhängigkeit des Befehls stehen unter Umständen weitere Felder oder Widgets zur Verfügung.&lt;br /&gt;
).&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 condition  ====&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz | RNTyp=y | RNText=Bei der Abfrage von Readings nach Strings (on, off, etc.) ist statt &amp;quot;=&amp;quot; &amp;quot;eq&amp;quot; zu nutzen und der String muss in &amp;quot;x&amp;quot; gesetzt werden. Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&#039;&#039;&#039;Achtung:&#039;&#039;&#039; Bei Anwendung der geschweiften Klammern zur Einleitung eines Perl Ausdrucks ist unbedingt auf die Leerzeichen hinter und vor der Klammer zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (zum Beispiel würde auch am Mittwoch noch der Schaltvorgang erfolgen, wenn als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
}} &lt;br /&gt;
Die Ausführung der Befehle kann &#039;&#039;&#039;pro gewählten Gerät&#039;&#039;&#039; analog Rahmen 1 von weiteren Bedingungen abhängig gemacht werden. Es gelten die gleichen Regeln und Beispiele wie im &#039;Rahmen 1 Trigger Conditions&#039;. Sie können sinngemäß übernommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Variable &amp;lt;code&amp;gt;$EVENT&amp;lt;/code&amp;gt; enthält den auslösenden Trigger. Wenn unter &#039;Rahmen 1 Trigger Conditions&#039; ein Wildcard verwendet wurde, kann nun feingefiltert werden, indem das konkrete Ereignis angegeben wird. &lt;br /&gt;
&lt;br /&gt;
Beispiel: &amp;lt;code&amp;gt;[$EVENT] eq &amp;quot;state:on&amp;quot;&amp;lt;/code&amp;gt; würde den Kommandozweig nur dann ausführen, wenn der auslösende Trigger &amp;quot;state:on&amp;quot; war.&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 delay  ====&lt;br /&gt;
Ein Eintrag in diesem Feld führt zur verzögerten Ausführung des Befehls nach Eintreffen des Events. Dabei kann der Befehl ohne weitere Prüfung der Bedingung ausgelöst werden. Es ist aber auch möglich, dass die Bedingung bei Ausführung erneut geprüft wird. Die Zeitangabe muss im Format hh:mm:ss vorliegen. Einzelheiten enthält auch das Funktions-Struktogramm.&lt;br /&gt;
&lt;br /&gt;
Statt einer direkten Zeitangabe kann hier auch auf eine verwiesen werden, indem in der Form [NAME.reading] ein Reading eines Devices wie z.B. [dummy.state] angegeben wird.&lt;br /&gt;
&lt;br /&gt;
==== add action  ====&lt;br /&gt;
Mit diesem Button kann ein weiterer Rahmen 4 als Rahmen 4.1 für das gleiche Device angelegt werden, um z.B. einen weiteren Befehl gegebenenfalls zeitverzögert auszuführen.&lt;br /&gt;
&lt;br /&gt;
==== delete this action  ====&lt;br /&gt;
Mit diesem Button wird der gewählte Rahmen 4 für das Device gelöscht.&lt;br /&gt;
&lt;br /&gt;
==== check condition  ====&lt;br /&gt;
[[Datei:MSwitch_Screen_7.png|mini|rechts|check]]&lt;br /&gt;
Die angegebenen &#039;conditions&#039; werden in Zusammenhang mit ggf. ausgewählten Devices auf Syntax und Ergebnis geprüft. Es erfolgt eine Ausgabe des Prüfungsergebnisses.&lt;br /&gt;
&lt;br /&gt;
==== Repeat und Repeatdelay ====&lt;br /&gt;
&lt;br /&gt;
Die Felder &#039;Repeats&#039;, &#039;Repeatdelay in s&#039; und &#039;priority&#039; stehen zur Verfügung, wenn das Attribut MSwitch_Expert gesetzt wurde. Diese bewirken eine n-fache Wiederholung des gesetzten Befehls mit m Sekunden Verzögerung. Das Auswahlfeld &#039;priority&#039; erscheint bei jedem &#039;affectes device&#039;. So kann die Reihenfolge der Befehlsabarbeitung beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
== Erweiterte Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Set-Befehle ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name !! class=&amp;quot;unsortable&amp;quot; | Beschreibung &lt;br /&gt;
|-&lt;br /&gt;
|set active||Setzt das MSwitch-Device in den Status &#039;active&#039;.&lt;br /&gt;
|-&lt;br /&gt;
|set inactive||Setzt das Device in den Status &#039;inactive&#039;. Es werden keine Befehle mehr ausgeführt. Dieser Status entspricht dem Attribut &#039;disable&#039;, ist aber nicht mit dem roten Fragezeichen (fhem save) verbunden.&lt;br /&gt;
|-&lt;br /&gt;
|set on&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;off [&amp;lt;parameter&amp;gt;]||Setzt das Device in den Status &#039;on&#039; oder &#039;off&#039;. Alle Befehle der &#039;on/off-Zweige&#039; werden ausgeführt. Optional kann den Befehlen &#039;on&#039; und &#039;off&#039; ein weiterer Parameter mit übergeben werden. Dieser wird im Reading &#039;Parameter&#039; hinterlegt und es kann sofort in &#039;Freecmds&#039; oder &#039;Conditions&#039; darauf zugegriffen werden.&lt;br /&gt;
|-&lt;br /&gt;
|set reload_timer||Alle gesetzten Timer werden gelöscht und neu berechnet.&lt;br /&gt;
|-&lt;br /&gt;
|set change_renamed &amp;lt;oldname&amp;gt; &amp;lt;newname&amp;gt;||Sollten sich Devicenammen im ausführenden Teil geändert habe (affected Devices, Conditions, etc.) so kann das MSwitch mit diesem Befehl angepasst werden, ohne alle Einstellungen neu einstellen zu müssen.&lt;br /&gt;
|-&lt;br /&gt;
|set exec_cmd1 &amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; set exec_cmd1 ID [&amp;lt;ID&amp;gt;]||Bewirkt das sofortige Ausführen des entsprechenden Befehlszweiges. Bei Angabe einer ID werden nur die Befehle mit der entsprechenden ID ausgeführt.&lt;br /&gt;
|-&lt;br /&gt;
|set MSwitch_backup||Erstellt eine Backup-Datei aller MSwitch Devices unter ./fhem/MSwitch_backup.cfg. Daten dieser Datei können im Bedarfsfall für einzelne oder gleichzeitig alle MSwitch Devices wieder zurückgespielt (hergestellt) werden.&lt;br /&gt;
|-&lt;br /&gt;
|set del_delays &amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; set exec_cmd1 ID [&amp;lt;ID&amp;gt;]||Löscht alle anstehenden, verzögerten Befehle (delays).&lt;br /&gt;
|-&lt;br /&gt;
|set reset_cmd_count: 1&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;2||Löscht das entsprechende EVT_CMD_COUNT - Reading; entspricht damit einer Rückstellung auf &#039;0&#039;.&lt;br /&gt;
|-&lt;br /&gt;
|set fakeevent [&amp;lt;device&amp;gt;]:&amp;lt;reading&amp;gt;:&amp;lt;arg&amp;gt;||Beispiel: &amp;lt;device&amp;gt; fakeevent state:on&amp;lt;br&amp;gt;&lt;br /&gt;
Das MSwitch Device reagiert so, als wäre statt des internen &amp;quot;fakes-Befehls&amp;quot; ohne FHEM-Systembeeinflussung dieses Event tatsächlich vom triggernden Gerät generiert worden. &lt;br /&gt;
&lt;br /&gt;
Der Name (&amp;lt;device&amp;gt;) muss bei GLOBALEN Triggern mit angegeben werden, sonst wird das Device automatisch gesetzt.&lt;br /&gt;
Um z.B. einen Watchdog zu realisieren ist es eventuell nötig, dass sich das MSwitch Device mit einem bestimmten Event selber neu triggert - ggf. mit einem entsprechenden Delay Affected Device. Bei dem Einsatz dieser Möglichkeit sollte das Attribut &#039;MSwitch_Safemode&#039; UNBEDINGT aktiviert sein, da &#039;Experimente&#039; hier schnell in einer Endlosschleife enden können, die nur durch ein Reboot unterbrochen werden kann. Möglicherweise steht dieser Befehl zukünftig nur noch zur Verfügung, wenn Safemode aktiviert ist.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Get-Befehle ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name !! class=&amp;quot;unsortable&amp;quot; | Beschreibung &lt;br /&gt;
|-&lt;br /&gt;
|get show_timer [&amp;lt;show&amp;gt;&amp;lt;delete&amp;gt;]||&lt;br /&gt;
;Show&lt;br /&gt;
:Zeigt alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren.&lt;br /&gt;
;Delete&lt;br /&gt;
:Löscht alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren. Schaltbefehle basierend auf rein zeitabhängigen Angaben werden neu berechnet und gesetzt.&lt;br /&gt;
|-&lt;br /&gt;
|get restore_MSwitch_data [&amp;lt;this_device&amp;gt;&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;&amp;lt;all_devices&amp;gt;]||&lt;br /&gt;
;this_device&lt;br /&gt;
:Stellt die Daten des Devices aus der Backupdatei wieder her, sofern diese in der Backupdatei gefunden werden (gesucht wird hier nach dem Namen des Devices).&lt;br /&gt;
;all_devices&lt;br /&gt;
:Stellt die Daten aller MSwitch Devices wieder her, sofern diese in der Backupdatei vorhanden sind. Diese Aktion kann einige Zeit in Anspruch nehmen und wird daher im Hintergrund (nonblocking) ausgeführt. Nach Beendigung erfolgt eine Benachrichtigung.&lt;br /&gt;
Die Devices sind nach einem Restore funktionsfähig. Empfohlen wird ein Neustart von FHEM..&lt;br /&gt;
|-&lt;br /&gt;
|get_config||Zeigt die Konfigurationsdatei des MSwitchdevices an; diese kann in dem Fenster editiert werden. Das sollte nur von erfahrenen Usern getan werden! Im Normalfall sollte das Device nur über die Weboberfläche konfiguriert werden und eine falsche Konfiguration kann hier zu einem FHEM Absturz führen.&lt;br /&gt;
|-&lt;br /&gt;
|get_support_info||Öffnet ein Fenster mit einer formatierten Ansicht aller Einstellungen des Devices. Bei Supportanfragen sollte dieses immer mit geposted werden.&lt;br /&gt;
|-&lt;br /&gt;
|get_MSwitch_preconf||Lädt vorkonfigurierte MSwitch-Devices. Diese Option ist nur dann vorhanden, wenn das Aktualisieren dieser vorkonfigurierten Devices im FHEM Update aktiviert ist.&lt;br /&gt;
Diese kann durch ein einmaliges Update erfolgen mit:&lt;br /&gt;
:&amp;lt;code&amp;gt;update all https://raw.githubusercontent.com/Byte009/MSwitch_Addons/master/controls_mswitchaddons.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Attribute ===&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name !! class=&amp;quot;unsortable&amp;quot; | Beschreibung &lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Debug &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;2&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;3&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;4&amp;gt;||&lt;br /&gt;
0 - Abgeschaltet&amp;lt;br&amp;gt;&lt;br /&gt;
1 - Schaltet Felder zum testen der Conditionstrings an&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Alle ausgehenden Befehle werden nur simuliert und nicht ausgeführt. Der Inhalt der Protokolldatei wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
3 - Es erfolgt eine Protokollierung in einer separaten Datei. Diese wird direkt im Device angezeigt.&amp;lt;br&amp;gt;&lt;br /&gt;
4 - erweitertes Debugfür Entwickler mit wechselnden Funktionen&amp;lt;br&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Expert &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt;||&lt;br /&gt;
* In der Liste der möglichen Trigger erscheint das Selectfeld &#039;GLOBAL&#039;. Dieses ermöglicht das Setzen eines Triggers auf alle Events und damit nicht nur auf einzelne Devices. In einem weiteren Feld kann eine weitere Selektion der triggernden Events erfolgen.&lt;br /&gt;
&lt;br /&gt;
* Die Felder &#039;Repeats&#039; und &#039;Repeatdelay in s&#039; stehen zur Verfügung. Dies bewirkt eine n-fache Wiederholung des gesetzten Befehls mit m Sekunden Verzögerung.&lt;br /&gt;
&lt;br /&gt;
* Das Auswahlfeld &#039;priority&#039; erscheint bei jedem &#039;affectes device&#039;. So kann die Reihenfolge der Befehlsabarbeitung beeinflusst werden.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Sequenz &amp;lt;Suchmuster&amp;gt; ??? ||&lt;br /&gt;
Eine Schaltsequenz kann durch ein oder mehrere durch &#039;/&#039; getrennte Suchmuster angegeben werden. Die Angabe muss folgende Syntax haben:&lt;br /&gt;
:&amp;lt;code&amp;gt;Device1:reading1:event1 Device1:reading1:event1-2 Device1:reading1:event1-3/..../....&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel: &amp;lt;code&amp;gt;Dummy:state:on Dummy:state:off Dummy:state:on&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erkennt das Device dieses Suchmuster in den Schaltvorgängen des Devices (Dummy), wird das Reading &amp;quot;SEQUENCE&amp;quot; auf &amp;quot;match&amp;quot; gesetzt, das Reading &amp;quot;SEQUENCE_NUMBER&amp;quot; auf die Nummer der gefundenen Sequenz, wenn es mehrere Suchmuster gibt. Beide Readings können in den &amp;quot;Conditions&amp;quot; eines Schaltbefehles abgefragt werden. Eine Angabe muss in folgendem Format gemacht werden:&lt;br /&gt;
:&amp;lt;code&amp;gt;on/off/state/suchmuster1/suchmuster2&amp;lt;/code&amp;gt;, wobei die letzten drei Angaben optional sind.&lt;br /&gt;
&lt;br /&gt;
Funktion: Bei Ausführung des Befehls wird das Gerät &#039;on&#039; oder &#039;off&#039; geschaltet (on/off), Voraussetzung ist, dass der &#039;state&#039; dieses Gerätes auch den &#039;state on&#039; oder &#039;off&#039; annimmt. Sollte dieses nicht der Fall sein, so kann mit dem Feld &#039;state&#039; angegeben werden, in welchem Reading der aktuelle Status vorkommt und wie dieser lautet (suchmuster1/suchmuster2). Dieses &#039;state&#039; kann mehrere Angaben enthalten, das Vorkommen der Suchmuster ist aber Voraussetzung.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Sequence_time &amp;lt;Zeit in Sekunden&amp;gt;||Maximalzeit in Sekunden, um eine Sequenz vollständig auszuführen. (Was wenn diese Zeit überschritten wird???)&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Extensions &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt;||Es wird zusätzlich zu &#039;on&#039; und &#039;off&#039; die Schaltoption &#039;MSwitchToggle&#039; in der Liste angeboten, um die Toggle-Funktion bei Geräten die sie nicht von Haus aus anbieten nachzurüsten.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Delete_Delays &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt;||Eins bewirkt das Löschen aller anstehende Delays bei dem Auftreten eines erneuten passenden Events. Bei der Option &#039;0&#039; bleiben bereits gesetzte Delays aus einem vorher getriggerten Event erhalten und werden ausgeführt. Empfohlene Einstellung: 1&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Include_Devicecmds &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt;||Bewirkt die Aufnahme aller Devices die bei Abfrage mit &#039;set DEVICE ?&#039; einen eigenen Befehlssatz liefern in die Auswahlliste &#039;Affected Devices&#039;. Bei Option &#039;0&#039; werden diese Devices in der Liste nicht mehr angeboten. Empfohlene Einstellung: 1&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Include_Webcmds &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt;||Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut Webcmd hinterlegt haben. Die in Webcmd hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten. Bei gesetzter Option &#039;0&#039; werden diese Devices nicht mehr angeboten, es sei denn, sie liefern mit &#039;set DEVICE ?&#039; einen eigenen Befehlssatz. Empfohlene Einstellung: 0, Einsatz nach Bedarf.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Activate_MSwitchcmds &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt;||Fügt jedem vorhandenen Device das Attribut &#039;MSwitchcmd&#039; hinzu.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Include_MSwitchcmds &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt; ||Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut MSwitchcmds hinterlegt haben. Die in MSwitchcmds hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten. Bei gesetzter Option &#039;0&#039; werden diese Devices nicht mehr angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz mit &#039;set DEVICE ?&#039; liefern. Empfohlene Einstellung: 0, Einsatz nach Bedarf.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Lock_Quickedit &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt;||Voreinstellung für die Auswahlliste &#039;Affected Devices&#039;. Bei der Option &#039;1&#039; ist diese voreingestellt gesperrt und kann nur über einen zusätzlichen Button geändert werden, um versehentliche Änderungen zu vermeiden. Die Auswahl einer Option ohne betätigte &amp;lt;Strg&amp;gt;-Taste bewirkt das Löschen aller bereits gesetzten Optionen. Empfohlene Einstellung: 1&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Startdelay &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;10&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;20&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;30&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;60&amp;gt; ||MSwitch ignoriert nach einem FHEM-Neustart für die angegebene Zeit in Sekunden alle eingehenden Events um u.a. Startverzögerungen zu vermeiden. Bei nicht gesetztem Attribut gilt hier eine Zeit von 30 Sekunden. Diese sollte auch nur in Ausnahmefällen geändert werden. Empfohlene Einstellung: 30&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Ignore_Types||Beinhaltet eine durch Leerzeichen getrennte Liste von Device-&#039;&#039;Typen&#039;&#039; welche nicht geschaltet werden oder nicht geschaltet werden können. Sie werden dann in den Auswahllisten &#039;&#039;nicht&#039;&#039; dargestellt, um die Auswahllisten übersichtlich zu halten.Voreinstellung: notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul. &lt;br /&gt;
&lt;br /&gt;
???Wenn statt des Devicetyps ein devspec z.B. &amp;quot;TYPE=watchdog&amp;quot; angegeben wird, ist zu beachten, dass alle Geräte in die Ignoreliste einbezogen werden, die NICHT der devspec entsprechen. Weiterhin muss die devspec in Anführungszeichen gesetzt werden!???&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Trigger_Filter  ||Beinhaltet eine kommagetrennte Liste von Events, die im Falle ihres Eingangs unberücksichtigt und ungespeichert bleiben. Wildcards wie &#039;*&#039; können angegeben werden. Empfohlene Einstellung: -&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Wait &amp;lt;n in Sekunden&amp;gt;||Bei gesetztem Attribut nimmt das MSwitch Device für den eingestellten Zeitraum keine Befehle mehr entgegen und ignoriert eingehende Events.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Event_Id_Distributor|| ??? Voraussetzung ist, dass das Attribut &#039;MSwitchExpert&#039; auf &#039;1&#039; gesetzt ist. Es können auslösende Events ID-Aktionen umgeleitet werden. Sollte bei den &#039;trigger details :&#039; in einem Zweig ( cmd1 ) z.B. mehrere getriggert werden (regex state:(on |off)) so werden für beide Events jeweils der Zweig &#039;cmd1&#039; - alle  Aktionen ohne ID - ausgeführt. Durch entsprechende Einträge kann für entsprechende Events auf eine Aktion umgeleitet werden, für die eine ID definiert ist. Die Syntax lautet: &amp;lt;code&amp;gt;state:on=&amp;gt;cmd1 ID 1,2&amp;lt;/code&amp;gt; Entsprechend werden bei auslösendem Event &#039;state:on&#039; nur die Aktionen aus cmd1 mit den IDs 1 und 2 ausgeführt. Mehrere Angaben sind durch new Line zu trennen. ???&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Selftrigger_always &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt; ||(dieses Attribut steht ab Modulversion 2.5 zur Verfügung)&lt;br /&gt;
&lt;br /&gt;
Die Aktivierung dieses Attributes &#039;1&#039; bewirkt, dass alle SET Aktionen des Devices einen internen Event ohne Auswirkungen auf das FHEM-System auslösen, auf die das Device selber reagiert. Diese Option kann zusätzlich zu einem vorhandenen Trigger aktiviert werden. Auftretende auswertbare interne Events haben immer folgendes Format: &lt;br /&gt;
MSwitch_Self:aktion:wert &lt;br /&gt;
MSwitch_Self:pct:100&lt;br /&gt;
Es werden nur interne Events für set-Aktionen ausgelöst, die im Attribut setlist hinterlegt sind. Der &#039;wait&#039; Befehl/Attribut hat keine wirkung.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Mode &amp;lt;Notify&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;Full&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;Toggle&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;Dummy&amp;gt; ||Schaltet das Modul zwischen angepassten Weboberflächen-Modi um.&lt;br /&gt;
&lt;br /&gt;
Notify&lt;br /&gt;
Das Device kann nicht manuell umgeschaltet werden. Es gibt nur die zwei ausführbaren Zweige &amp;quot;execute &#039;cmd1&#039; commands&amp;quot; und &amp;quot;execute &#039;cmd2&#039; commands&amp;quot;. Der Status des Devices wird nicht als &#039;on&#039; oder &#039;off&#039; angezeigt, sondern lediglich als &#039;active&#039; Dieser Mode ist ähnlich zu einem FHEM-Notify.&lt;br /&gt;
&lt;br /&gt;
Full&lt;br /&gt;
Es stehen alle Funktionen zur Verfügung.&lt;br /&gt;
Toggle&lt;br /&gt;
Sehr vereinfachter Mode. Es stehen keine verschiedenen Zweige zur Verfügung. Hier ist das Device manuell schaltbar und wird bei jedem definierten Event &#039;umgeschaltet&#039;, ??? entsprechend definierte Befehle für &#039;cmd1&#039; oder &#039;cmd2&#039; werden ausgeführt. ???&lt;br /&gt;
Dummy&lt;br /&gt;
ACHTUNG: Funktionsänderung mit V2.61 Der Mode &#039;Dummy&#039; ist ein eingeschränkter Modus. Dieser bietet die Funktionalität eines Dummys kombiniert mit der Funktionalität eines Notifys und kann somit die gerne genutzte Kombination Dummy-Notify gegen ein Device ersetzen. Der Dummy-Mode kann nur in einem neu angelegten leeren MSwitch aktiviert und auch nicht wieder verlassen werden! Sobald ein angelegtes MSwitch einmal verändert wurde (modify trigger etc.) sind Umschalt-Optionen nicht mehr verfügbar.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Condition_Time &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt; ||In der Grundeinstellung &#039;0&#039; werden für das zeitgesteuerte Schalten keine definierten Conditionen im Feld &#039;Trigger condition&#039; überprüft, sondern die Schaltbefehle werden in jedem Fall ausgeführt. Mit der Einstellung &#039;1&#039; wird diese Überprüfung wie für Events zugeschaltet.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Random_Time &amp;lt;HH:MM:SS-HH:MM:SS&amp;gt; || Bei Aktivierung wird vor jedem Ausführen eines verzögerten Befehls (Delay) eine Zufallszeit generiert, die im Rahmen der hier angegebenen Zeitspanne liegt. Auf diese Zufallszahl kann in den Delays zugegriffen werden, durch die Angabe &#039;[random]&#039; statt einer direkten Zeitangabe. Bei nicht gesetztem Attribut ergibt die Angabe von &#039;[random]&#039; immer &#039;00:00:00&#039;&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MMSwitch_Random_Number &amp;lt;n&amp;gt; ||Bei Aktivierung dieses Attributes mit einer beliebigen ganzen Zahl, werden vom Device die zwei Readings  &#039;RandomNr&#039; und &#039;RandomNr1&#039; und mit Werten zwischen null und n angelegt. RandomNr wird vor jedem Ausführen eines Befehls, auch für unterschiedliche Geräte in einem Durchgang, neu generiert. RandomNr1 bleibt nach der Initialisierung konstant. Wenn auf dieses Readings in einer Condition mit z.B. &#039;[$NAME:ReadingNr1] = 1&#039; zugegriffen wird, wird der Befehl nur ausgeführt, wenn ReadingNr1 gerade = 1 ist. Der Befehl wird somit nur mit einer Wahrscheinlichkeit von eins zu n ausgeführt.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Reset_EVT_CMD1(2)_COUNT ||Bei Aktivierung dieses Attributes steht in den Readings das Reading &#039;EVT_CMD1_COUNT&#039; bzw. &#039;EVT_CMD2_COUNT&#039; zur Verfügung. Dieses kann in den Conditions genutzt werden, um z.B. nur bei jedem x-ten Eintreffen eines auslösenden Events einen Befehl auszuführen. Bei jedem Eintreffen eines gültigen Events werden die Zähler um 1 erhöht (für den jeweiligen Zweig). Ist hier der Wert &#039;0&#039; eingetragen, wird der Zähler fortlaufend (endlos) erhöht. Wird ein Wert größer 0 eingetragen, wird der Zähler mit Erreichen dieses Wertes automatisch wieder auf Null gesetzt. Mit Löschen dieses Attributes werden die entsprechenden Readings ebenfalls gelöscht.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Safemode &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt; ||Bietet einen gewissen Schutz vor falschen Konfigurationen und dadurch entstehenden Endlosschleifen. Bei aktiviertem Attribut &#039;1&#039; beendet das Modul Endlosschleifen eines Devices. In diesem Fall erfolgt ein Logeintrag und das Device wird per Attribut auf &#039;Disabled&#039; gesetzt. Es wird ein letztes Event generiert, auf das reagiert werden kann &amp;lt;code&amp;gt;2018-05-31 09:39:21 MSwitch &amp;lt;NAME&amp;gt; Safemode: on&amp;lt;/code&amp;gt; Im Webinterface erfolgt bei betroffenem Device ein entsprechender Hinweis. In der Grundkonfiguration ist dieses Attribut nicht gesetzt. Es empfiehlt sich aber, bei neuen bzw. komplizierten Devices, dieses zumindest anfänglich zu aktivieren.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Read_Log&amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt; ||Ermöglicht den Zugriff auf das Logfile als Trigger.&lt;br /&gt;
&lt;br /&gt;
* Bei aktiviertem Attribut enthält die Auswahl des Triggerdevices die Option &#039;LOGFILE&#039;. Bei dieser Auswahl werde alle Logeinträge erkannt und in ein internes Event umgewandelt, auf das regiert werden kann.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl &#039;GLOBAL&#039; im &#039;Trigger_Device&#039; wird auf ALLE Events und alle Logeinträge reagiert.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl eines bestimmten Devices im &#039;Trigger_Device&#039; wird auf alle Events  und auf alle Logeinträge des gewählten Devices reagiert. Der im Logeintrag vorhandene Devicename ist Bedingung für die Funktion.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Help&amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt; ||Schaltet Hilfebuttons zu den einzelnen Eingabefeldern an oder aus.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Comments&amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt; ||Schaltet Kommentarfelder zu den einzelnen &#039;affected_devices an.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_generate_Events&amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt; ||Reduziert bei Einstellung &#039;1&#039; die vom MSwitch-Devices erzeugten Events auf ein Minimum. Insbesondere bei Verwendung von &#039;MSwitch_Read_Log&#039; zu empfehlen.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Startdelay||???Bestimmt die Verzögerungszeit des MSwitches nach FHEM-Start in Sekunden. In diesem Zeitraum reagiert das Device nicht auf Events. Die Vorgabe ist hier zehn Sekunden. Diese wird auch dann angenommen, wenn das Attribut nicht gesetzt ist.??? (Hatten wir das nicht schon?)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Inforoom  ||Mit diesem Attribut wird die Raumansicht eines mit dem Attribut bestimmten Raumes verändert. Dadurch sollen die wichtigsten Informationen aller MSwitch-Devices auf eine Seite dargestellt werden. Zur Nutzung sollten alle MSwitch-Devices (zusätzlich) in einen Raum sortiert werden und dieser Raum im Attribut eingestellt werden.&lt;br /&gt;
&lt;br /&gt;
Wichtig: Eine Änderung dieses Attributes bewirkt immer eine Änderung dieses Attributes in &#039;&#039;allen&#039;&#039; MSwitch devices: Es muss nur in einem Device gesetzt oder gelöscht werden um alle Devices zu erfassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
MSwitch_Screen_1.png|Raumansicht des Raumes MSwitch mit gesetztem Attribut &#039;MSwitch&#039;&lt;br /&gt;
MSwitch_Screen_2.png|Raumansicht des Raumes MSwitch ohne gesetztes Attribut&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es werden folgende Informationen bereitgestellt:&lt;br /&gt;
* Infobutton zeigt den im Device gespeicherten Textes des Attributes &#039;comment&#039;&lt;br /&gt;
* Device und Events, die das Device triggern&lt;br /&gt;
* Zeiten, zu denen verschiedene Zweige des Devices ausgeführt werden&lt;br /&gt;
* Devices, die durch das MSwitch Device geschaltet werden&lt;br /&gt;
* State des Devices&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Integrierte Funktionen ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name !! class=&amp;quot;unsortable&amp;quot; | Beschreibung &lt;br /&gt;
|-&lt;br /&gt;
|Average||???&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
|Difference||&lt;br /&gt;
* Syntax: [DIFF&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;differenz&amp;gt;&lt;br /&gt;
* Beispiel: [DIFF2:countdown] &amp;gt; 0&lt;br /&gt;
* Reading: entspricht dem getriggerten Reading.&lt;br /&gt;
* Wert: gespeicherter Wert (in diesem Fall der vorletzte).&lt;br /&gt;
* Differenz: geforderte Differenz zwischen aktuellem und vorletztem Wert.&lt;br /&gt;
* Schaltung erfolg wenn diese Bedingung &#039;wahr&#039; ist.&lt;br /&gt;
Folgende Readings werden zur Verfügung gestellt:&lt;br /&gt;
* DIFFERENCE (true/false) - Schaltbedingung erkannt ja/nein&lt;br /&gt;
* DIFFDIRECTION (up/down) - Richtung der erkannten Bedingung (steigend/fallend)&lt;br /&gt;
|-&lt;br /&gt;
|Increase||???&lt;br /&gt;
|-&lt;br /&gt;
|Tendency||&lt;br /&gt;
*Syntax: [TEND&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;Mindestwert&amp;gt;&lt;br /&gt;
*Beispiel: [TEND2:countdown] &amp;gt; 2&lt;br /&gt;
*Reading: entspricht dem getriggerten Reading.&lt;br /&gt;
*Wert: Es wird jeweils der Durchschnitt von 2 Wertepaaren gebildet. In diesem Fall werden die letzten 4 Werte herangezogen. Paar 1 = Aktueller und letzter Wert, Paar 2 = Die 2 vorherigen Werte. Bei TEND3 werden die letzten 6 Werte zur Paarbildung genutzt.&lt;br /&gt;
*Mindestwert: Der Wertunterschied zwischen den Wertepaaren, der minimal erreicht sein muss, um eine Tendenz zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Rechenzeichen (&amp;gt;&amp;lt;):&lt;br /&gt;
Dieses ist hier nicht als Rechenzeichen zu werten, sonder als Tendenz-Anzeige. ( &amp;lt; es wird nach fallender Tendenz gesucht / &amp;gt; sucht nach steigender Tendenz).&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolgt einmalig bei Erkennung der gesuchten Tendenz.&lt;br /&gt;
Danach erfolgt keine Schaltung mehr, solange bis eine Tendenz-Umkehr erfolgt ist.&lt;br /&gt;
Erst dann erfolgt wieder eine Schaltung bei erneuter Tendenz-Umkehr in gesuchte Richtung.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Funktions-Struktogramm ==&lt;br /&gt;
[[Datei:MSwitch full.svg|Struktogramm des Funktionsprinzips]]&lt;br /&gt;
&lt;br /&gt;
== Anwendungs-Beispiele ==&lt;br /&gt;
&lt;br /&gt;
=== [[Blinken - Rechteckgenerator]] ===&lt;br /&gt;
=== [[Blinken - Impulsgenerator mit variablem Tastgrad]] ===&lt;br /&gt;
=== [[Schmitt-Trigger - Temperaturabhängiges Schalten]] ===&lt;br /&gt;
=== [[Linearschalter]] ===&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Thread über das Modul im {{Link2Forum|Topic=86199|LinkText=FHEM Forum}}&lt;br /&gt;
* {{Link2Forum|Topic=100119|Message=936495|LinkText=Gäste-WLAN der Fritzbox auswerten und Login per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=86199|Message=930133|LinkText=Schalten von vier Kanälen mit einem MSwitch-Device}}&lt;br /&gt;
* {{Link2Forum|Topic=99219|Message=926652|LinkText=Batterie-Überwachung. 1xTäglich per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=101091|Message=945389|LinkText=Licht (Alarm) in einem bestimmten Zeitraum schalten}}&lt;br /&gt;
* {{Link2Forum|Topic=100949|Message=944284|LinkText=Über Dummy-Schalter ein Timer (EIN/AUS) aktivieren}}&lt;br /&gt;
* {{Link2Forum|Topic=103083|Message=967710|LinkText=Ladezeit von Akku ermitteln u. Steckdose entsprechend schalten}}&lt;br /&gt;
* {{Link2Forum|Topic=86199|Message=990265|LinkText=Bewegungsmelder}}&lt;br /&gt;
* {{Link2Forum|Topic=86199|Message=974592|LinkText=Rauch und Hitzemelder steuern}}&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=AT_um_eine_Temperaturabh%C3%A4ngige_Nachtabsenkung_zu_realisieren&amp;diff=33367</id>
		<title>AT um eine Temperaturabhängige Nachtabsenkung zu realisieren</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=AT_um_eine_Temperaturabh%C3%A4ngige_Nachtabsenkung_zu_realisieren&amp;diff=33367"/>
		<updated>2020-06-07T19:45:45Z</updated>

		<summary type="html">&lt;p&gt;Maista: drei &amp;quot;war&amp;quot; in einem Satz&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Für die Grundlegende Funktion von [[at]] bitte einen Blick in die {{Link2CmdRef|Anker=at}} werfen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ins&amp;gt;Zielvorgabe:&amp;lt;/ins&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jeden Tag um 22:30 soll die Temperatur auf 17° abgesenkt werden (hier das FHEM-Gerät &amp;quot;wz_Heizung&amp;quot;) wenn die Temperatur vorher über 17° eingestellt war - war die Temperatur vorher niedriger eingestellt, soll nichts passieren.&lt;br /&gt;
&lt;br /&gt;
Der Befehl für die [[Konfiguration]] lautet dazu wie folgt:&lt;br /&gt;
&lt;br /&gt;
Einzeiler:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;define wz_HeizungNachtabsenkung at 22:30:00 {if(ReadingsVal(&#039;wz_Heizung&#039;, &#039;desired-temp&#039;, 0) &amp;amp;gt; 17.0) {fhem(&amp;amp;quot;set wz_Heizung desired-temp 17.0&amp;amp;quot;)} }&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mehrzeiler:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;define wz_HeizungNachtabsenkung at 22:30:00 {\&lt;br /&gt;
  if(ReadingsVal(&#039;wz_Heizung&#039;, &#039;desired-temp&#039;, 0) &amp;amp;gt; 17.0) {\&lt;br /&gt;
   fhem(&amp;amp;quot;set wz_Heizung desired-temp 17.0&amp;amp;quot;)\&lt;br /&gt;
  }\&lt;br /&gt;
 }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Im Detail:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;define wz_HeizungNachtabsenkung&#039;&#039; =&amp;amp;gt; lege ein neues Objekt &#039;&#039;wz_HeizungNachtabsenkung&#039;&#039; und ...&lt;br /&gt;
* &#039;&#039;at *22:30:00&#039;&#039; =&amp;amp;gt; ... prüfe täglich um 22:30 Uhr ...&lt;br /&gt;
* &#039;&#039;if(ReadingsVal(&#039;wz_Heizung&#039;, &#039;desired-temp&#039;, 0) &amp;amp;gt; 17.0&#039;&#039; =&amp;amp;gt; ... ob &#039;&#039;(ReadingsVal -&amp;amp;gt; lese Werte)&#039;&#039; ...&amp;lt;br&amp;gt;&#039;&#039;(&#039;wz_Heizung&#039;, &#039;desired-temp&#039;, 0)&#039;&#039;=&amp;amp;gt; ... ob am Gerät &#039;&#039;wz_Heizung&#039;&#039;der Wert &#039;&#039;desired-temp&#039;&#039;...&amp;lt;br&amp;gt;&#039;&#039;&amp;amp;gt; 17.0&#039;&#039;=&amp;amp;gt; ... größer als 17.0 ist, wenn ja dann ...&lt;br /&gt;
* &#039;&#039;fhem(&amp;quot;set wz_Heizung desired-temp 17.0&amp;quot;)&#039;&#039; =&amp;amp;gt; ... soll FHEM am Gerät &#039;&#039;wz_Heizung&#039;&#039; den Wert &#039;&#039;desired-temp&#039;&#039; auf 17.0° setzen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Anmerkung zu ReadingsVal:&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;ReadingsVal(&amp;amp;lt;DeviceName&amp;amp;gt;, &amp;amp;lt;ReadingsName&amp;amp;gt;, &amp;amp;lt;Defaultwert&amp;amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Damit wird das entsprechende Reading am entsprechenden Device ausgelesen. Gibt es das Reading nicht, wird Defaultwert zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
Man kann Prozedurergebnisse (wie dieses von ReadingsVal) und Variablen bei Vergleichen natürlich mischen, und muss diese Ergebnisse nicht unbedingt in Variablen zwischenspeichern. Das tut man meistens nur, wenn das Ermitteln viel Zeit in Anspruch nimmt und man diesen mehrfach benötigt, oder der Wert durch Überschreiben verloren geht.&lt;br /&gt;
&lt;br /&gt;
Perl hat als Besonderheit, dass man einer Variablen nicht ansieht, ob sie eine Zahl oder einen String enthält. Das sind alles sogenannte Skalare (im Gegensatz zu Arrays oder Hashlisten). Um bei einem Vergleich aber die durchaus unterschiedlichen Ergebnisse erzwingen zu können, gibt es eben unterschiedliche Operatoren dafür:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;amp;lt;, &amp;amp;gt;, &amp;amp;lt;=, &amp;amp;gt;=, ==,&amp;amp;#160;!= sind numerische Operatoren&lt;br /&gt;
 lt, gt, le, ge, eq, ne sind die entsprechenden Stringvergleichsoperatoren&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;my $var1 = &#039;10&#039;;&lt;br /&gt;
 my $var2 = &#039;2&#039;;&lt;br /&gt;
 # Ergibt true:&lt;br /&gt;
 if ($var1 &amp;amp;gt; $var2)...&lt;br /&gt;
 # Ergibt false:&lt;br /&gt;
 if ($var1 gt $var2)...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Für weitere Beispiele bietet es sich an auch mal einen Blick in die &#039;&#039;fhem.pl &#039;&#039;zu werfen.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=List&amp;diff=33272</id>
		<title>List</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=List&amp;diff=33272"/>
		<updated>2020-05-23T20:46:20Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* list -r */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:list}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Befehl zur Auflistung von Gerätedefinitionen&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=list&lt;br /&gt;
|ModForumArea=Sonstiges&lt;br /&gt;
|ModTechName=fhem.pl (&amp;quot;Built-in&amp;quot;)&lt;br /&gt;
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
Der Befehl [[list]] dient dazu, Informationen über Geräte (Devices) anzuzeigen. Dabei können entweder Details zu einem einzelnen Gerät ausgegeben werden, oder eine Liste von Geräten (Gerätenamen) mit bestimmten gemeinsamen Attributen. Wenn mehrere Geräte aufgelistet werden, lässt sich zu jedem zusätzlich der Wert eines oder mehrerer Internals, Readings oder Attribute mit ausgeben.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann direkt über das Eingabefeld des [[FHEMWEB|Webfrontends]] oder über die telnet Schnittstelle eingegeben werden. &lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
{{Randnotiz|RNText=Für alle Beispiele gilt: im Webfrontend lassen sich die Namen der ausgegebenen Geräte direkt anklicken, um in die zugehörige Detail-Ansicht zu gelangen. Dies ist besonders für [[weblink]], [[SVG]] oder [[readingsGroup]] Geräte nützlich, die in der Raum-Ansicht eventuell keinen solchen Link auf die Detail-Ansicht zeigen.}}&lt;br /&gt;
=== Alle Geräte mit bestimmten Namen mit ihrer Definition ===&lt;br /&gt;
Auflistung der Definitionen aller Geräte von FHEM:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list .* DEF&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auflistung der Definitionen der Geräte, die mit wz beginnen.&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list wz.* DEF&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte eines bestimmten Typs ===&lt;br /&gt;
Mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list TYPE=FS20&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
wird eine Liste (die Namen) aller Geräte des Typs [[FS20]] ausgegeben. &lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte ohne TYPE ===&lt;br /&gt;
Manche Fehlersituationen in FHEM werden verursacht durch Geräte, bei denen kein &#039;&#039;Internal&#039;&#039; mit dem Namen &#039;&#039;TYPE&#039;&#039; festgelegt ist (was eigentlich eine ungültige Definition ist). Diese Geräte-Definitionen lassen sich mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{ join(&amp;quot;\n&amp;quot;, grep { !defined($defs{$_}{TYPE}) } keys %defs) }&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
identifizieren. Mithilfe dieser Information lässt sich dann z.B. ein solches Gerät [[delete|löschen]]. &lt;br /&gt;
&lt;br /&gt;
Ein derartiges Szenario ist unter anderem in diesem {{Link2Forum|Topic=41137|LinkText=Forenthema}} beschrieben.&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte mit einem bestimmten Attribut ===&lt;br /&gt;
Im Zusammenhang mit Verhaltensänderungen eines Attributs (wie z.B. bei [[userReadings]] geschehen), kann es sinnvoll sein, alle Devices aufzulisten, bei denen dieses Attribut verwendet wurde.&lt;br /&gt;
;alle Devices, bei denen das Attribut &#039;&#039;userReadings&#039;&#039; (auf einen beliebigen Wert gesetzt) ist:&lt;br /&gt;
:&amp;lt;code&amp;gt;list userReadings=[a-zA-Z].*&amp;lt;/code&amp;gt; oder &amp;lt;br /&amp;gt;&amp;lt;code&amp;gt;list userReadings=.+&amp;lt;/code&amp;gt; oder &amp;lt;br /&amp;gt;&amp;lt;code&amp;gt;list userReadings=\w.*&amp;lt;/code&amp;gt; oder &amp;lt;br /&amp;gt;&amp;lt;code&amp;gt;list userReadings=..*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte in einem Raum ===&lt;br /&gt;
[[Datei:ListRoom.png|mini|right|Ausgabebeispiel eines &#039;&#039;list&#039;&#039; Befehls]]&lt;br /&gt;
Mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list room=TV&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
werden die Namen aller Geräte aufgeführt, die ein Attribut &#039;&#039;room&#039;&#039; mit dem Wert &#039;&#039;TV&#039;&#039; haben. Durch einen Klick auf den Gerätenamen wird die Detailansicht des Gerätes aufgerufen.&lt;br /&gt;
&lt;br /&gt;
=== Attributwert zu mehreren Geräten ===&lt;br /&gt;
Mit dem Befehl&lt;br /&gt;
:&amp;lt;code&amp;gt;list TYPE=CUL_HM serialNr&amp;lt;/code&amp;gt;&lt;br /&gt;
werden die Seriennummern aller Homematic Geräte aufgelistet.&lt;br /&gt;
&lt;br /&gt;
=== Mehrere Werte zu mehreren Geräten ===&lt;br /&gt;
Mit dem Befehl&lt;br /&gt;
:&amp;lt;code&amp;gt;list TYPE=CUL_HM:FILTER=serialNr=..* serialNr model&amp;lt;/code&amp;gt;&lt;br /&gt;
werden die Seriennummer und die Modellbezeichnung aller Homematic Geräte aufgelistet, die auch eine Seriennummer haben.&lt;br /&gt;
&lt;br /&gt;
=== Gezieltes Auflisten von Internal, Reading oder Attribut ===&lt;br /&gt;
Bei manchen Geräten gibt es Internals, Readings oder Attribute mit gleichem Namen. Da &#039;&#039;list&#039;&#039; jeweils nur das erste Vorkommen zeigt und nicht sichtbar macht, was genau gefunden wurde, ist die Ausgabe manchmal nicht eindeutig. Um das zu vermeiden, lässt sich mit dem Präfix i:, r: oder a: vor dem Namen des anzuzeigenden Wertes angeben, welcher der drei möglichen Typen ausgegeben werden soll.&lt;br /&gt;
&lt;br /&gt;
== Erweiterte Optionen ==&lt;br /&gt;
Mit den Optionen -r und -R kann eine erweiterte Ausgabe erzielt werden. Diese sollte bei der Erstellung eines Threads im Forum zu allen beteiligten Geräten mit angegeben werden. Die Optionen können auch hilfreich sein, um Teile der [[Konfiguration]] schnell zwischen unterschiedlichen Installationen zu kopieren, z.B. von einem oder in ein Testsystem (siehe auch [[Import von Code Snippets]]). &lt;br /&gt;
=== list -r ===&lt;br /&gt;
Dabei werden auch die derzeitigen Stände der Readings mit ausgegeben. Für die Angabe des Gerätenamens ist dabei die Verwendung jeder {{Link2CmdRef|Anker=devspec|Label=devspec}} zulässig.&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list -r TV&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list -r&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== list -R ===&lt;br /&gt;
Mit dieser Option werden auch die Geräte samt aktueller Zustände mit ausgegeben, die als &#039;&#039;&#039;probably associated with&#039;&#039; erkannt worden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list -R TV&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* [[Import von Code Snippets|RAW Definition]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:FHEM-Verwendung]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=List&amp;diff=33271</id>
		<title>List</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=List&amp;diff=33271"/>
		<updated>2020-05-23T20:43:58Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* list -r */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:list}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Befehl zur Auflistung von Gerätedefinitionen&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=list&lt;br /&gt;
|ModForumArea=Sonstiges&lt;br /&gt;
|ModTechName=fhem.pl (&amp;quot;Built-in&amp;quot;)&lt;br /&gt;
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
Der Befehl [[list]] dient dazu, Informationen über Geräte (Devices) anzuzeigen. Dabei können entweder Details zu einem einzelnen Gerät ausgegeben werden, oder eine Liste von Geräten (Gerätenamen) mit bestimmten gemeinsamen Attributen. Wenn mehrere Geräte aufgelistet werden, lässt sich zu jedem zusätzlich der Wert eines oder mehrerer Internals, Readings oder Attribute mit ausgeben.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann direkt über das Eingabefeld des [[FHEMWEB|Webfrontends]] oder über die telnet Schnittstelle eingegeben werden. &lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
{{Randnotiz|RNText=Für alle Beispiele gilt: im Webfrontend lassen sich die Namen der ausgegebenen Geräte direkt anklicken, um in die zugehörige Detail-Ansicht zu gelangen. Dies ist besonders für [[weblink]], [[SVG]] oder [[readingsGroup]] Geräte nützlich, die in der Raum-Ansicht eventuell keinen solchen Link auf die Detail-Ansicht zeigen.}}&lt;br /&gt;
=== Alle Geräte mit bestimmten Namen mit ihrer Definition ===&lt;br /&gt;
Auflistung der Definitionen aller Geräte von FHEM:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list .* DEF&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auflistung der Definitionen der Geräte, die mit wz beginnen.&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list wz.* DEF&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte eines bestimmten Typs ===&lt;br /&gt;
Mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list TYPE=FS20&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
wird eine Liste (die Namen) aller Geräte des Typs [[FS20]] ausgegeben. &lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte ohne TYPE ===&lt;br /&gt;
Manche Fehlersituationen in FHEM werden verursacht durch Geräte, bei denen kein &#039;&#039;Internal&#039;&#039; mit dem Namen &#039;&#039;TYPE&#039;&#039; festgelegt ist (was eigentlich eine ungültige Definition ist). Diese Geräte-Definitionen lassen sich mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{ join(&amp;quot;\n&amp;quot;, grep { !defined($defs{$_}{TYPE}) } keys %defs) }&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
identifizieren. Mithilfe dieser Information lässt sich dann z.B. ein solches Gerät [[delete|löschen]]. &lt;br /&gt;
&lt;br /&gt;
Ein derartiges Szenario ist unter anderem in diesem {{Link2Forum|Topic=41137|LinkText=Forenthema}} beschrieben.&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte mit einem bestimmten Attribut ===&lt;br /&gt;
Im Zusammenhang mit Verhaltensänderungen eines Attributs (wie z.B. bei [[userReadings]] geschehen), kann es sinnvoll sein, alle Devices aufzulisten, bei denen dieses Attribut verwendet wurde.&lt;br /&gt;
;alle Devices, bei denen das Attribut &#039;&#039;userReadings&#039;&#039; (auf einen beliebigen Wert gesetzt) ist:&lt;br /&gt;
:&amp;lt;code&amp;gt;list userReadings=[a-zA-Z].*&amp;lt;/code&amp;gt; oder &amp;lt;br /&amp;gt;&amp;lt;code&amp;gt;list userReadings=.+&amp;lt;/code&amp;gt; oder &amp;lt;br /&amp;gt;&amp;lt;code&amp;gt;list userReadings=\w.*&amp;lt;/code&amp;gt; oder &amp;lt;br /&amp;gt;&amp;lt;code&amp;gt;list userReadings=..*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte in einem Raum ===&lt;br /&gt;
[[Datei:ListRoom.png|mini|right|Ausgabebeispiel eines &#039;&#039;list&#039;&#039; Befehls]]&lt;br /&gt;
Mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list room=TV&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
werden die Namen aller Geräte aufgeführt, die ein Attribut &#039;&#039;room&#039;&#039; mit dem Wert &#039;&#039;TV&#039;&#039; haben. Durch einen Klick auf den Gerätenamen wird die Detailansicht des Gerätes aufgerufen.&lt;br /&gt;
&lt;br /&gt;
=== Attributwert zu mehreren Geräten ===&lt;br /&gt;
Mit dem Befehl&lt;br /&gt;
:&amp;lt;code&amp;gt;list TYPE=CUL_HM serialNr&amp;lt;/code&amp;gt;&lt;br /&gt;
werden die Seriennummern aller Homematic Geräte aufgelistet.&lt;br /&gt;
&lt;br /&gt;
=== Mehrere Werte zu mehreren Geräten ===&lt;br /&gt;
Mit dem Befehl&lt;br /&gt;
:&amp;lt;code&amp;gt;list TYPE=CUL_HM:FILTER=serialNr=..* serialNr model&amp;lt;/code&amp;gt;&lt;br /&gt;
werden die Seriennummer und die Modellbezeichnung aller Homematic Geräte aufgelistet, die auch eine Seriennummer haben.&lt;br /&gt;
&lt;br /&gt;
=== Gezieltes Auflisten von Internal, Reading oder Attribut ===&lt;br /&gt;
Bei manchen Geräten gibt es Internals, Readings oder Attribute mit gleichem Namen. Da &#039;&#039;list&#039;&#039; jeweils nur das erste Vorkommen zeigt und nicht sichtbar macht, was genau gefunden wurde, ist die Ausgabe manchmal nicht eindeutig. Um das zu vermeiden, lässt sich mit dem Präfix i:, r: oder a: vor dem Namen des anzuzeigenden Wertes angeben, welcher der drei möglichen Typen ausgegeben werden soll.&lt;br /&gt;
&lt;br /&gt;
== Erweiterte Optionen ==&lt;br /&gt;
Mit den Optionen -r und -R kann eine erweiterte Ausgabe erzielt werden. Diese sollte bei der Erstellung eines Threads im Forum zu allen beteiligten Geräten mit angegeben werden. Die Optionen können auch hilfreich sein, um Teile der [[Konfiguration]] schnell zwischen unterschiedlichen Installationen zu kopieren, z.B. von einem oder in ein Testsystem (siehe auch [[Import von Code Snippets]]). &lt;br /&gt;
=== list -r ===&lt;br /&gt;
Dabei werden auch die derzeitigen Stände der Readings mit ausgegeben. Für die Angabe des Gerätenamens ist dabei die Verwendung jeder {{Link2CmdRef|Anker=devspec|Label=devspec}} zulässig.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list -r TV&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list -r&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== list -R ===&lt;br /&gt;
Mit dieser Option werden auch die Geräte samt aktueller Zustände mit ausgegeben, die als &#039;&#039;&#039;probably associated with&#039;&#039; erkannt worden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list -R TV&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* [[Import von Code Snippets|RAW Definition]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:FHEM-Verwendung]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=List&amp;diff=33270</id>
		<title>List</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=List&amp;diff=33270"/>
		<updated>2020-05-23T20:43:13Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* list -r */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:list}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Befehl zur Auflistung von Gerätedefinitionen&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=list&lt;br /&gt;
|ModForumArea=Sonstiges&lt;br /&gt;
|ModTechName=fhem.pl (&amp;quot;Built-in&amp;quot;)&lt;br /&gt;
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
Der Befehl [[list]] dient dazu, Informationen über Geräte (Devices) anzuzeigen. Dabei können entweder Details zu einem einzelnen Gerät ausgegeben werden, oder eine Liste von Geräten (Gerätenamen) mit bestimmten gemeinsamen Attributen. Wenn mehrere Geräte aufgelistet werden, lässt sich zu jedem zusätzlich der Wert eines oder mehrerer Internals, Readings oder Attribute mit ausgeben.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann direkt über das Eingabefeld des [[FHEMWEB|Webfrontends]] oder über die telnet Schnittstelle eingegeben werden. &lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
{{Randnotiz|RNText=Für alle Beispiele gilt: im Webfrontend lassen sich die Namen der ausgegebenen Geräte direkt anklicken, um in die zugehörige Detail-Ansicht zu gelangen. Dies ist besonders für [[weblink]], [[SVG]] oder [[readingsGroup]] Geräte nützlich, die in der Raum-Ansicht eventuell keinen solchen Link auf die Detail-Ansicht zeigen.}}&lt;br /&gt;
=== Alle Geräte mit bestimmten Namen mit ihrer Definition ===&lt;br /&gt;
Auflistung der Definitionen aller Geräte von FHEM:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list .* DEF&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auflistung der Definitionen der Geräte, die mit wz beginnen.&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list wz.* DEF&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte eines bestimmten Typs ===&lt;br /&gt;
Mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list TYPE=FS20&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
wird eine Liste (die Namen) aller Geräte des Typs [[FS20]] ausgegeben. &lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte ohne TYPE ===&lt;br /&gt;
Manche Fehlersituationen in FHEM werden verursacht durch Geräte, bei denen kein &#039;&#039;Internal&#039;&#039; mit dem Namen &#039;&#039;TYPE&#039;&#039; festgelegt ist (was eigentlich eine ungültige Definition ist). Diese Geräte-Definitionen lassen sich mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{ join(&amp;quot;\n&amp;quot;, grep { !defined($defs{$_}{TYPE}) } keys %defs) }&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
identifizieren. Mithilfe dieser Information lässt sich dann z.B. ein solches Gerät [[delete|löschen]]. &lt;br /&gt;
&lt;br /&gt;
Ein derartiges Szenario ist unter anderem in diesem {{Link2Forum|Topic=41137|LinkText=Forenthema}} beschrieben.&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte mit einem bestimmten Attribut ===&lt;br /&gt;
Im Zusammenhang mit Verhaltensänderungen eines Attributs (wie z.B. bei [[userReadings]] geschehen), kann es sinnvoll sein, alle Devices aufzulisten, bei denen dieses Attribut verwendet wurde.&lt;br /&gt;
;alle Devices, bei denen das Attribut &#039;&#039;userReadings&#039;&#039; (auf einen beliebigen Wert gesetzt) ist:&lt;br /&gt;
:&amp;lt;code&amp;gt;list userReadings=[a-zA-Z].*&amp;lt;/code&amp;gt; oder &amp;lt;br /&amp;gt;&amp;lt;code&amp;gt;list userReadings=.+&amp;lt;/code&amp;gt; oder &amp;lt;br /&amp;gt;&amp;lt;code&amp;gt;list userReadings=\w.*&amp;lt;/code&amp;gt; oder &amp;lt;br /&amp;gt;&amp;lt;code&amp;gt;list userReadings=..*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte in einem Raum ===&lt;br /&gt;
[[Datei:ListRoom.png|mini|right|Ausgabebeispiel eines &#039;&#039;list&#039;&#039; Befehls]]&lt;br /&gt;
Mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list room=TV&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
werden die Namen aller Geräte aufgeführt, die ein Attribut &#039;&#039;room&#039;&#039; mit dem Wert &#039;&#039;TV&#039;&#039; haben. Durch einen Klick auf den Gerätenamen wird die Detailansicht des Gerätes aufgerufen.&lt;br /&gt;
&lt;br /&gt;
=== Attributwert zu mehreren Geräten ===&lt;br /&gt;
Mit dem Befehl&lt;br /&gt;
:&amp;lt;code&amp;gt;list TYPE=CUL_HM serialNr&amp;lt;/code&amp;gt;&lt;br /&gt;
werden die Seriennummern aller Homematic Geräte aufgelistet.&lt;br /&gt;
&lt;br /&gt;
=== Mehrere Werte zu mehreren Geräten ===&lt;br /&gt;
Mit dem Befehl&lt;br /&gt;
:&amp;lt;code&amp;gt;list TYPE=CUL_HM:FILTER=serialNr=..* serialNr model&amp;lt;/code&amp;gt;&lt;br /&gt;
werden die Seriennummer und die Modellbezeichnung aller Homematic Geräte aufgelistet, die auch eine Seriennummer haben.&lt;br /&gt;
&lt;br /&gt;
=== Gezieltes Auflisten von Internal, Reading oder Attribut ===&lt;br /&gt;
Bei manchen Geräten gibt es Internals, Readings oder Attribute mit gleichem Namen. Da &#039;&#039;list&#039;&#039; jeweils nur das erste Vorkommen zeigt und nicht sichtbar macht, was genau gefunden wurde, ist die Ausgabe manchmal nicht eindeutig. Um das zu vermeiden, lässt sich mit dem Präfix i:, r: oder a: vor dem Namen des anzuzeigenden Wertes angeben, welcher der drei möglichen Typen ausgegeben werden soll.&lt;br /&gt;
&lt;br /&gt;
== Erweiterte Optionen ==&lt;br /&gt;
Mit den Optionen -r und -R kann eine erweiterte Ausgabe erzielt werden. Diese sollte bei der Erstellung eines Threads im Forum zu allen beteiligten Geräten mit angegeben werden. Die Optionen können auch hilfreich sein, um Teile der [[Konfiguration]] schnell zwischen unterschiedlichen Installationen zu kopieren, z.B. von einem oder in ein Testsystem (siehe auch [[Import von Code Snippets]]). &lt;br /&gt;
=== list -r ===&lt;br /&gt;
Dabei werden auch die derzeitigen Stände der Readings mit ausgegeben. Für die Angabe des Gerätenamens ist dabei die Verwendung jeder {{Link2CmdRef|Anker=devspec|Label=devspec}} zulässig.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list -r TV&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list -r .*&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== list -R ===&lt;br /&gt;
Mit dieser Option werden auch die Geräte samt aktueller Zustände mit ausgegeben, die als &#039;&#039;&#039;probably associated with&#039;&#039; erkannt worden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list -R TV&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* [[Import von Code Snippets|RAW Definition]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:FHEM-Verwendung]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=List&amp;diff=33269</id>
		<title>List</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=List&amp;diff=33269"/>
		<updated>2020-05-23T20:40:03Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* list -R */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:list}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Befehl zur Auflistung von Gerätedefinitionen&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=list&lt;br /&gt;
|ModForumArea=Sonstiges&lt;br /&gt;
|ModTechName=fhem.pl (&amp;quot;Built-in&amp;quot;)&lt;br /&gt;
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
Der Befehl [[list]] dient dazu, Informationen über Geräte (Devices) anzuzeigen. Dabei können entweder Details zu einem einzelnen Gerät ausgegeben werden, oder eine Liste von Geräten (Gerätenamen) mit bestimmten gemeinsamen Attributen. Wenn mehrere Geräte aufgelistet werden, lässt sich zu jedem zusätzlich der Wert eines oder mehrerer Internals, Readings oder Attribute mit ausgeben.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann direkt über das Eingabefeld des [[FHEMWEB|Webfrontends]] oder über die telnet Schnittstelle eingegeben werden. &lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
{{Randnotiz|RNText=Für alle Beispiele gilt: im Webfrontend lassen sich die Namen der ausgegebenen Geräte direkt anklicken, um in die zugehörige Detail-Ansicht zu gelangen. Dies ist besonders für [[weblink]], [[SVG]] oder [[readingsGroup]] Geräte nützlich, die in der Raum-Ansicht eventuell keinen solchen Link auf die Detail-Ansicht zeigen.}}&lt;br /&gt;
=== Alle Geräte mit bestimmten Namen mit ihrer Definition ===&lt;br /&gt;
Auflistung der Definitionen aller Geräte von FHEM:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list .* DEF&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auflistung der Definitionen der Geräte, die mit wz beginnen.&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list wz.* DEF&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte eines bestimmten Typs ===&lt;br /&gt;
Mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list TYPE=FS20&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
wird eine Liste (die Namen) aller Geräte des Typs [[FS20]] ausgegeben. &lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte ohne TYPE ===&lt;br /&gt;
Manche Fehlersituationen in FHEM werden verursacht durch Geräte, bei denen kein &#039;&#039;Internal&#039;&#039; mit dem Namen &#039;&#039;TYPE&#039;&#039; festgelegt ist (was eigentlich eine ungültige Definition ist). Diese Geräte-Definitionen lassen sich mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{ join(&amp;quot;\n&amp;quot;, grep { !defined($defs{$_}{TYPE}) } keys %defs) }&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
identifizieren. Mithilfe dieser Information lässt sich dann z.B. ein solches Gerät [[delete|löschen]]. &lt;br /&gt;
&lt;br /&gt;
Ein derartiges Szenario ist unter anderem in diesem {{Link2Forum|Topic=41137|LinkText=Forenthema}} beschrieben.&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte mit einem bestimmten Attribut ===&lt;br /&gt;
Im Zusammenhang mit Verhaltensänderungen eines Attributs (wie z.B. bei [[userReadings]] geschehen), kann es sinnvoll sein, alle Devices aufzulisten, bei denen dieses Attribut verwendet wurde.&lt;br /&gt;
;alle Devices, bei denen das Attribut &#039;&#039;userReadings&#039;&#039; (auf einen beliebigen Wert gesetzt) ist:&lt;br /&gt;
:&amp;lt;code&amp;gt;list userReadings=[a-zA-Z].*&amp;lt;/code&amp;gt; oder &amp;lt;br /&amp;gt;&amp;lt;code&amp;gt;list userReadings=.+&amp;lt;/code&amp;gt; oder &amp;lt;br /&amp;gt;&amp;lt;code&amp;gt;list userReadings=\w.*&amp;lt;/code&amp;gt; oder &amp;lt;br /&amp;gt;&amp;lt;code&amp;gt;list userReadings=..*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte in einem Raum ===&lt;br /&gt;
[[Datei:ListRoom.png|mini|right|Ausgabebeispiel eines &#039;&#039;list&#039;&#039; Befehls]]&lt;br /&gt;
Mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list room=TV&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
werden die Namen aller Geräte aufgeführt, die ein Attribut &#039;&#039;room&#039;&#039; mit dem Wert &#039;&#039;TV&#039;&#039; haben. Durch einen Klick auf den Gerätenamen wird die Detailansicht des Gerätes aufgerufen.&lt;br /&gt;
&lt;br /&gt;
=== Attributwert zu mehreren Geräten ===&lt;br /&gt;
Mit dem Befehl&lt;br /&gt;
:&amp;lt;code&amp;gt;list TYPE=CUL_HM serialNr&amp;lt;/code&amp;gt;&lt;br /&gt;
werden die Seriennummern aller Homematic Geräte aufgelistet.&lt;br /&gt;
&lt;br /&gt;
=== Mehrere Werte zu mehreren Geräten ===&lt;br /&gt;
Mit dem Befehl&lt;br /&gt;
:&amp;lt;code&amp;gt;list TYPE=CUL_HM:FILTER=serialNr=..* serialNr model&amp;lt;/code&amp;gt;&lt;br /&gt;
werden die Seriennummer und die Modellbezeichnung aller Homematic Geräte aufgelistet, die auch eine Seriennummer haben.&lt;br /&gt;
&lt;br /&gt;
=== Gezieltes Auflisten von Internal, Reading oder Attribut ===&lt;br /&gt;
Bei manchen Geräten gibt es Internals, Readings oder Attribute mit gleichem Namen. Da &#039;&#039;list&#039;&#039; jeweils nur das erste Vorkommen zeigt und nicht sichtbar macht, was genau gefunden wurde, ist die Ausgabe manchmal nicht eindeutig. Um das zu vermeiden, lässt sich mit dem Präfix i:, r: oder a: vor dem Namen des anzuzeigenden Wertes angeben, welcher der drei möglichen Typen ausgegeben werden soll.&lt;br /&gt;
&lt;br /&gt;
== Erweiterte Optionen ==&lt;br /&gt;
Mit den Optionen -r und -R kann eine erweiterte Ausgabe erzielt werden. Diese sollte bei der Erstellung eines Threads im Forum zu allen beteiligten Geräten mit angegeben werden. Die Optionen können auch hilfreich sein, um Teile der [[Konfiguration]] schnell zwischen unterschiedlichen Installationen zu kopieren, z.B. von einem oder in ein Testsystem (siehe auch [[Import von Code Snippets]]). &lt;br /&gt;
=== list -r ===&lt;br /&gt;
Dabei werden auch die derzeitigen Stände der Readings mit ausgegeben. Für die Angabe des Gerätenamens ist dabei die Verwendung jeder {{Link2CmdRef|Anker=devspec|Label=devspec}} zulässig.&lt;br /&gt;
=== list -R ===&lt;br /&gt;
Mit dieser Option werden auch die Geräte samt aktueller Zustände mit ausgegeben, die als &#039;&#039;&#039;probably associated with&#039;&#039; erkannt worden sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list -R TV&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* [[Import von Code Snippets|RAW Definition]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:FHEM-Verwendung]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=List&amp;diff=33268</id>
		<title>List</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=List&amp;diff=33268"/>
		<updated>2020-05-23T20:14:03Z</updated>

		<summary type="html">&lt;p&gt;Maista: n entfernt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:list}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Befehl zur Auflistung von Gerätedefinitionen&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=list&lt;br /&gt;
|ModForumArea=Sonstiges&lt;br /&gt;
|ModTechName=fhem.pl (&amp;quot;Built-in&amp;quot;)&lt;br /&gt;
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
Der Befehl [[list]] dient dazu, Informationen über Geräte (Devices) anzuzeigen. Dabei können entweder Details zu einem einzelnen Gerät ausgegeben werden, oder eine Liste von Geräten (Gerätenamen) mit bestimmten gemeinsamen Attributen. Wenn mehrere Geräte aufgelistet werden, lässt sich zu jedem zusätzlich der Wert eines oder mehrerer Internals, Readings oder Attribute mit ausgeben.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann direkt über das Eingabefeld des [[FHEMWEB|Webfrontends]] oder über die telnet Schnittstelle eingegeben werden. &lt;br /&gt;
&lt;br /&gt;
== Beispiele ==&lt;br /&gt;
{{Randnotiz|RNText=Für alle Beispiele gilt: im Webfrontend lassen sich die Namen der ausgegebenen Geräte direkt anklicken, um in die zugehörige Detail-Ansicht zu gelangen. Dies ist besonders für [[weblink]], [[SVG]] oder [[readingsGroup]] Geräte nützlich, die in der Raum-Ansicht eventuell keinen solchen Link auf die Detail-Ansicht zeigen.}}&lt;br /&gt;
=== Alle Geräte mit bestimmten Namen mit ihrer Definition ===&lt;br /&gt;
Auflistung der Definitionen aller Geräte von FHEM:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list .* DEF&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auflistung der Definitionen der Geräte, die mit wz beginnen.&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list wz.* DEF&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte eines bestimmten Typs ===&lt;br /&gt;
Mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list TYPE=FS20&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
wird eine Liste (die Namen) aller Geräte des Typs [[FS20]] ausgegeben. &lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte ohne TYPE ===&lt;br /&gt;
Manche Fehlersituationen in FHEM werden verursacht durch Geräte, bei denen kein &#039;&#039;Internal&#039;&#039; mit dem Namen &#039;&#039;TYPE&#039;&#039; festgelegt ist (was eigentlich eine ungültige Definition ist). Diese Geräte-Definitionen lassen sich mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{ join(&amp;quot;\n&amp;quot;, grep { !defined($defs{$_}{TYPE}) } keys %defs) }&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
identifizieren. Mithilfe dieser Information lässt sich dann z.B. ein solches Gerät [[delete|löschen]]. &lt;br /&gt;
&lt;br /&gt;
Ein derartiges Szenario ist unter anderem in diesem {{Link2Forum|Topic=41137|LinkText=Forenthema}} beschrieben.&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte mit einem bestimmten Attribut ===&lt;br /&gt;
Im Zusammenhang mit Verhaltensänderungen eines Attributs (wie z.B. bei [[userReadings]] geschehen), kann es sinnvoll sein, alle Devices aufzulisten, bei denen dieses Attribut verwendet wurde.&lt;br /&gt;
;alle Devices, bei denen das Attribut &#039;&#039;userReadings&#039;&#039; (auf einen beliebigen Wert gesetzt) ist:&lt;br /&gt;
:&amp;lt;code&amp;gt;list userReadings=[a-zA-Z].*&amp;lt;/code&amp;gt; oder &amp;lt;br /&amp;gt;&amp;lt;code&amp;gt;list userReadings=.+&amp;lt;/code&amp;gt; oder &amp;lt;br /&amp;gt;&amp;lt;code&amp;gt;list userReadings=\w.*&amp;lt;/code&amp;gt; oder &amp;lt;br /&amp;gt;&amp;lt;code&amp;gt;list userReadings=..*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte in einem Raum ===&lt;br /&gt;
[[Datei:ListRoom.png|mini|right|Ausgabebeispiel eines &#039;&#039;list&#039;&#039; Befehls]]&lt;br /&gt;
Mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;list room=TV&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
werden die Namen aller Geräte aufgeführt, die ein Attribut &#039;&#039;room&#039;&#039; mit dem Wert &#039;&#039;TV&#039;&#039; haben. Durch einen Klick auf den Gerätenamen wird die Detailansicht des Gerätes aufgerufen.&lt;br /&gt;
&lt;br /&gt;
=== Attributwert zu mehreren Geräten ===&lt;br /&gt;
Mit dem Befehl&lt;br /&gt;
:&amp;lt;code&amp;gt;list TYPE=CUL_HM serialNr&amp;lt;/code&amp;gt;&lt;br /&gt;
werden die Seriennummern aller Homematic Geräte aufgelistet.&lt;br /&gt;
&lt;br /&gt;
=== Mehrere Werte zu mehreren Geräten ===&lt;br /&gt;
Mit dem Befehl&lt;br /&gt;
:&amp;lt;code&amp;gt;list TYPE=CUL_HM:FILTER=serialNr=..* serialNr model&amp;lt;/code&amp;gt;&lt;br /&gt;
werden die Seriennummer und die Modellbezeichnung aller Homematic Geräte aufgelistet, die auch eine Seriennummer haben.&lt;br /&gt;
&lt;br /&gt;
=== Gezieltes Auflisten von Internal, Reading oder Attribut ===&lt;br /&gt;
Bei manchen Geräten gibt es Internals, Readings oder Attribute mit gleichem Namen. Da &#039;&#039;list&#039;&#039; jeweils nur das erste Vorkommen zeigt und nicht sichtbar macht, was genau gefunden wurde, ist die Ausgabe manchmal nicht eindeutig. Um das zu vermeiden, lässt sich mit dem Präfix i:, r: oder a: vor dem Namen des anzuzeigenden Wertes angeben, welcher der drei möglichen Typen ausgegeben werden soll.&lt;br /&gt;
&lt;br /&gt;
== Erweiterte Optionen ==&lt;br /&gt;
Mit den Optionen -r und -R kann eine erweiterte Ausgabe erzielt werden. Diese sollte bei der Erstellung eines Threads im Forum zu allen beteiligten Geräten mit angegeben werden. Die Optionen können auch hilfreich sein, um Teile der [[Konfiguration]] schnell zwischen unterschiedlichen Installationen zu kopieren, z.B. von einem oder in ein Testsystem (siehe auch [[Import von Code Snippets]]). &lt;br /&gt;
=== list -r ===&lt;br /&gt;
Dabei werden auch die derzeitigen Stände der Readings mit ausgegeben. Für die Angabe des Gerätenamens ist dabei die Verwendung jeder {{Link2CmdRef|Anker=devspec|Label=devspec}} zulässig.&lt;br /&gt;
=== list -R ===&lt;br /&gt;
Mit dieser Option werden auch die Geräte samt aktueller Zustände mit ausgegeben, die als &#039;&#039;&#039;probably associated with&#039;&#039; erkannt worden sind.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* [[Import von Code Snippets|RAW Definition]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:FHEM-Verwendung]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=EventTypes&amp;diff=33267</id>
		<title>EventTypes</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=EventTypes&amp;diff=33267"/>
		<updated>2020-05-23T16:33:48Z</updated>

		<summary type="html">&lt;p&gt;Maista: Fhem &amp;gt; FHEM&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:eventTypes}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Sammeln der Ereignistypen für alle definerten Geräte&lt;br /&gt;
|ModType=h&lt;br /&gt;
|ModForumArea=Frontends&lt;br /&gt;
|ModCmdRef=eventTypes&lt;br /&gt;
|ModTechName=91_eventTypes.pm&lt;br /&gt;
|ModOwner={{Link2FU|8|rudolfkoenig}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Das Hilfsmodul [[eventTypes]] sammelt die Ereignistypen für alle definierten Geräte (Devices) und speichert sie in der spezifizierten Datei. Die gesammelten Daten werden benutzt um auf der Benutzeroberfläche (z.B. bei der Bearbeitung eines [[notify]]) bei der Erstellung von regulären Ausrücken die möglichen Werte in Auswahllisten anzuzeigen.&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen ==&lt;br /&gt;
[[Datei:Hinweis_eventTypes.png|mini|rechts|Hinweis (Link) auf Informationen zu eventTypes]]&lt;br /&gt;
Für die Benutzung von eventTypes sind keine besonderen Voraussetzungen zu erfüllen, evenTypes ist jedoch im Gegenzug erforderlich, um Unterstützung bei der Erstellung von regulären Ausdrücken (Regexp wizard) bieten zu können.&lt;br /&gt;
&lt;br /&gt;
== Anwendung ==&lt;br /&gt;
=== Define ===&lt;br /&gt;
Siehe {{Link2CmdRef|Anker=eventTypesdefine}}.&lt;br /&gt;
&lt;br /&gt;
=== Attribute ===&lt;br /&gt;
Siehe {{Link2CmdRef|Anker=eventTypesattr}}.&lt;br /&gt;
&lt;br /&gt;
== Hinweise ==&lt;br /&gt;
Die Datei für die Sammlung der eventTypes kann nach einiger Zeit sehr groß werden. Auf leistungsschwächeren FHEM-Servern führt dies unter Umständen zu einer erheblichen Verzögerung beim Objektdetails-Aufruf der Objekte, die den Regex Wizard nutzen (bspw. [[notify]], [[at]]).&lt;br /&gt;
&lt;br /&gt;
Abhilfe: Löschen der eventTypes-Datei &lt;br /&gt;
 set &amp;lt;eventTypes-device&amp;gt; clear&lt;br /&gt;
 set &amp;lt;eventTypes-device&amp;gt; flush&lt;br /&gt;
&lt;br /&gt;
siehe auch: {{Link2Forum|Topic=33905}}&lt;br /&gt;
&lt;br /&gt;
== Anwendungsbeispiele ==&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=FileLog&amp;diff=33266</id>
		<title>FileLog</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=FileLog&amp;diff=33266"/>
		<updated>2020-05-23T16:30:38Z</updated>

		<summary type="html">&lt;p&gt;Maista: Fhem &amp;gt; FHEM&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Modul&lt;br /&gt;
|ModPurpose=Protokollierung von Fhem-Ereignissen&lt;br /&gt;
|ModType=h&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=92_FileLog.pm&lt;br /&gt;
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]])}}&lt;br /&gt;
&lt;br /&gt;
Das Modul [[FileLog]] dient zur Protokollierung von Ereignissen in FHEM. Die Einträge werden in eine einfache Textdatei geschrieben. Zur Protokollierung in eine Datenbank kann alternativ oder auch parallel das Modul [[DbLog]] verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Logdateien sind die Basis für die Erstellung von Diagrammen ([[SVG]]).&lt;br /&gt;
&lt;br /&gt;
== Definition ==&lt;br /&gt;
Details in der {{Link2CmdRef|Anker=FileLogdefine}}.&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Über {{Link2CmdRef|Anker=FileLogattr|Label=Attribute}} lässt sich unter anderem auch festlegen, wie die Archivierung von Logdateien durchgeführt werden soll (Archivierungsbefehl, -pfad sowie Anzahl von Archivgenerationen).&lt;br /&gt;
&lt;br /&gt;
Wenn bestimmte Zeilen &#039;&#039;&#039;nicht&#039;&#039;&#039; in die Logdatei geschrieben werden sollen, ist das Attribut &#039;&#039;ignoreRegexp&#039;&#039; hilfreich. Wenn beispielsweise alle Zeilen, die die Zeichenfolge &amp;quot;AbCd&amp;quot; oder &amp;quot;CdEf&amp;quot; enthalten &#039;&#039;&#039;nicht&#039;&#039;&#039; geloggt werden sollen, dann wäre&lt;br /&gt;
:&amp;lt;code&amp;gt;attr &amp;lt;log-name&amp;gt; ignoreRegexp .*AbCd.*|.*CdEf.*&amp;lt;/code&amp;gt;&lt;br /&gt;
eine Attributdefinition, die das ermöglicht.&lt;br /&gt;
&lt;br /&gt;
Dies bezieht sich aber nur auf normale FileLog-Instanzen. Falls Events aus dem globalen FHEM-Logfile ausgeschlossen werden sollen, muss man das Attribut in &#039;&#039;&#039;global&#039;&#039;&#039; angeben. (Zusammenhang siehe [[#Globale Logdatei und &amp;quot;fakelog&amp;quot;|Globale Logdatei und &amp;quot;fakelog&amp;quot;]]) &lt;br /&gt;
:&amp;lt;code&amp;gt;attr global ignoreRegexp .*AbCd.*|.*CdEf.*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Funktionen ==&lt;br /&gt;
&#039;&#039;FileLog&#039;&#039; bietet Funktionen wie &#039;&#039;reopen&#039;&#039;, &#039;&#039;absorb&#039;&#039; und &#039;&#039;get&#039;&#039;. Details dazu sind in der {{Link2CmdRef|Anker=FileLogset}} zu finden.&lt;br /&gt;
&lt;br /&gt;
Sofern eine Instanz vom Objekt [[eventTypes]] angelegt ist, bietet die Detailansicht eines FileLog eine komfortable Möglichkeit, die regulären Ausdrücke für den/die Filter zu bearbeiten. Siehe hierzu auch diesen {{Link2Forum|Topic=12557|Message=75436}}.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Globale Logdatei und &amp;quot;fakelog&amp;quot; ==&lt;br /&gt;
Die globale Logdatei (üblicherweise als fhem.log bezeichnet) für FHEM wird mit dem Attribut &lt;br /&gt;
:&amp;lt;code&amp;gt;attr global logfile XXX&amp;lt;/code&amp;gt;&lt;br /&gt;
für das &#039;&#039;global&#039;&#039;-Objekt definiert, wobei für &#039;&#039;XXX&#039;&#039; normalerweise &amp;lt;code&amp;gt;./log/fhem-%Y-%m.log&amp;lt;/code&amp;gt; verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Um das &#039;&#039;fhem.log&#039;&#039; über das [[FHEMWEB|Web Interface]] anzeigen zu können, ist ein weiterer Eintrag in der [[Konfiguration]] erforderlich, nämlich:&lt;br /&gt;
:&amp;lt;code&amp;gt;define Logfile FileLog XXX fakelog&amp;lt;/code&amp;gt;&lt;br /&gt;
Das &#039;&#039;XXX&#039;&#039; muss &#039;&#039;&#039;zwingend&#039;&#039;&#039; durch den gleichen Wert ersetzt werden, wie in der Definition des globalen &#039;&#039;logfile&#039;&#039; Attributs, weil anderenfalls unterschiedliche Dateien verwendet werden - mit dem Effekt, dass die über das Web Interface angezeigte Datei nicht die erwarteten Einträge enthält (Details dazu auch in diesem {{Link2Forum|Topic=40041|Message=323315|LinkText=Forenbeitrag}}).&lt;br /&gt;
&lt;br /&gt;
== Werte auslesen ==&lt;br /&gt;
Manchmal möchte man Daten aus den Logs abrufen ohne händisch in den Logfiles herumzuwühlen. Dies ist insb. auch dann hilfreich, wenn man eigenen Funktionen, Notifys oder spezielle Plots entwirft, bei denen man auf Logdaten zugreifen möchte.&lt;br /&gt;
&lt;br /&gt;
Grundsätzlich beschrieben ist dies in der {{Link2CmdRef|Lang=de|Anker=FileLog}} und unterscheidet sich minimal (aber entscheidend) von der Struktur bei [[DbLog#Werte_auslesen|DbLogs]].&lt;br /&gt;
&lt;br /&gt;
Hier ein paar Beispiele, was man damit anstellen kann:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;get FileLog_FHT_3a32 - - 2016-10-01 2016-10-03&amp;lt;/code&amp;gt; alle Einträge des FileLog_FHT_3a32 vom 01.10.-03.10.2016&lt;br /&gt;
* &amp;lt;code&amp;gt;get FileLog_FHT_3a32 - - 2016-10-01_08:00:00 2016-10-01_16:00:00&amp;lt;/code&amp;gt; alle Einträge des FileLog_FHT_3a32 von 8-16 Uhr am 01.10.2016&lt;br /&gt;
* &amp;lt;code&amp;gt;get FileLog_FHT_3a32 - - 2016-10-01_08:00:00 2016-10-01_16:00:00 4:measured:0:&amp;lt;/code&amp;gt; nur die Temperatur-Werte&lt;br /&gt;
* &amp;lt;code&amp;gt;{ ReadingsTimestamp(&amp;quot;FHT_3a32&amp;quot;,&amp;quot;state&amp;quot;,&amp;quot;0&amp;quot;) }&amp;lt;/code&amp;gt; Timestamp des aktuellen state des FHT_3a32&lt;br /&gt;
* &amp;lt;code&amp;gt;{ OldTimestamp(&amp;quot;FHT_3a32&amp;quot;) }&amp;lt;/code&amp;gt; Timestamp des letzten state des FHT_3a32&lt;br /&gt;
* &amp;lt;code&amp;gt;{ time_str2num(OldTimestamp(&amp;quot;FHT_3a32&amp;quot;)) }&amp;lt;/code&amp;gt; Timestamp in Sekunden des letzten state des FHT_3a32&lt;br /&gt;
* ...&lt;br /&gt;
Weitere Beispiele kann man sich gut aus den SVG-Dateien ziehen.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* {{Link2Forum|Topic=40041|Message=323315|LinkText=Forenbeitrag}} zum Thema fhem.log / fakelog&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Logging]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=ArduCounter&amp;diff=32259</id>
		<title>ArduCounter</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=ArduCounter&amp;diff=32259"/>
		<updated>2020-01-01T22:57:13Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Set-Commands */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Modul&lt;br /&gt;
|ModPurpose=Count pulses, calculate time between pulses and convert this to readings for e.g. power consumption of Energy meters&lt;br /&gt;
|ModType=contrib&lt;br /&gt;
|ModCmdRef=ArduCounter&lt;br /&gt;
|ModForumArea=Sonstiges&lt;br /&gt;
|ModFTopic=19285&lt;br /&gt;
|ModTechName=98_ArduCounter.pm&lt;br /&gt;
|ModOwner=StefanStrobel ({{Link2FU|3960|Forum}} / [[Benutzer:StefanStrobel|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
This module implements an Interface to an Arduino or ESP8266 based counter for pulses on any input pin of an Arduino Uno, Nano, Jeenode, NodeMCU, Wemos D1 or similar device. The device connects to FHEM either through USB / serial or via tcp if an ESP board is used.&lt;br /&gt;
&lt;br /&gt;
The typical use case is an S0-Interface on an energy meter or water meter, but also reflection light barriers to monitor old ferraris counters are supported&lt;br /&gt;
&lt;br /&gt;
Counters are configured with attributes that define which Arduino pins should count pulses and in which intervals the Arduino board should report the current counts.&lt;br /&gt;
&lt;br /&gt;
The Arduino sketch that works with this module uses pin change interrupts so it can efficiently count pulses on all available input pins.&lt;br /&gt;
The module creates readings for pulse counts, consumption and optionally also a pin history with pulse lengths and gaps of the last pulses.&lt;br /&gt;
&lt;br /&gt;
== Availability == &lt;br /&gt;
The module has been checked in to the FHEM svn. &lt;br /&gt;
The corresponding Arduino sketch can also be found under contrib in the subdirectory arduino/.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
This module requires an Arduino Uno, Nano, Jeenode, NodeMCU, Wemos D1 or similar device based on an Atmel 328p or ESP8266 running the ArduCounter sketch provided with this module&lt;br /&gt;
&lt;br /&gt;
In order to flash an Arduino board with the corresponding ArduCounter firmware from within Fhem, avrdude needs to be installed.&lt;br /&gt;
&lt;br /&gt;
For old ferraris counters an Arduino Uno or Nano or ESP8266 board needs to be connected to a reflection light barrier which consists simply of an infra red photo transistor (connected to A7 on Arduinos and A0 on ESP8266) and an infra red led (connected to D2 on Arduinos and to D6 on ESP8266), both with a resistor in line.&lt;br /&gt;
&lt;br /&gt;
This module also requires Device::SerialPort or Win32::SerialPort for communication via serial lines&lt;br /&gt;
&lt;br /&gt;
== Define ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;define &amp;lt;name&amp;gt; ArduCounter &amp;lt;device&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
&amp;lt;pre&amp;gt;define &amp;lt;name&amp;gt; ArduCounter &amp;lt;ip:port&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;device&amp;gt; specifies the serial port to communicate with the Arduino.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ip:port&amp;gt; specifies the ip address and tcp port to communicate with an esp8266 where port is typically 80.&lt;br /&gt;
&lt;br /&gt;
The name of the serial-device depends on your distribution. You can also specify a baudrate for serial connections if the device name contains the @ character, e.g.: /dev/ttyUSB0@38400. The default baudrate of the ArduCounter firmware is 38400 since Version 1.4&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define AC ArduCounter /dev/ttyUSB2@38400&lt;br /&gt;
define AC ArduCounter 192.168.1.134:80&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configuration of ArduCounter digital counters ==&lt;br /&gt;
&lt;br /&gt;
Specify the pins where impulses should be counted e.g. as attr AC pinX falling pullup 30&lt;br /&gt;
&lt;br /&gt;
The X in pinX can be an Arduino / ESP pin number with or without the letter D e.g. pin4, pinD5, pin6, pinD7 ...&lt;br /&gt;
&lt;br /&gt;
After the pin you can use the keywords falling or rising to define if a logical one / 5V (rising) or a logical zero / 0V (falling) should be treated as pulse.&lt;br /&gt;
&lt;br /&gt;
The optional keyword pullup activates the pullup resistor for the given Pin.&lt;br /&gt;
&lt;br /&gt;
The last argument is also optional but recommended and specifies a minimal pulse length in milliseconds.&lt;br /&gt;
&lt;br /&gt;
An energy meter with S0 interface is typically connected to GND and an input pin like D4.&lt;br /&gt;
The S0 pulse then pulls the input to 0V.&lt;br /&gt;
Since the minimal pulse lenght of the s0 interface is specified to be 30ms, the typical configuration for an s0 interface is&lt;br /&gt;
attr AC pinX falling pullup 30&lt;br /&gt;
&lt;br /&gt;
Specifying a minimal pulse length is recommended since it filters bouncing of reed contacts or other noise.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define AC ArduCounter /dev/ttyUSB2&lt;br /&gt;
attr AC pulsesPerKWh 1000&lt;br /&gt;
attr AC interval 60 300&lt;br /&gt;
attr AC pinD4 falling pullup 5&lt;br /&gt;
attr AC pinD5 falling pullup 30&lt;br /&gt;
attr AC verboseReadingsD5&lt;br /&gt;
attr AC pinD6 rising&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
This defines three counters connected to the pins D4, D5 and D5.&lt;br /&gt;
D4 and D5 have their pullup resistors activated and the impulse draws the pins to zero.&lt;br /&gt;
For D4 and D5 the arduino measures the time in milliseconds between the falling edge and the rising edge. If this time is longer than the specified 5 or 30 milliseconds then the impulse is counted.&lt;br /&gt;
If the time is shorter then this impulse is regarded as noise and added to a separate reject counter.&lt;br /&gt;
&lt;br /&gt;
verboseReadings5 causes the module to create additional readings like the pin history which shows length and gaps between the last pulses.&lt;br /&gt;
&lt;br /&gt;
For pin D6 the arduino does not check pulse lengths and counts every time when the signal changes from 0 to 1.&lt;br /&gt;
&lt;br /&gt;
The ArduCounter sketch which must be loaded on the Arduino or ESP implements this using pin change interrupts, so all avilable input pins can be used, not only the ones that support normal interrupts.&lt;br /&gt;
The module has been tested with 14 inputs of an Arduino Uno counting in parallel and pulses as short as 3 milliseconds.&lt;br /&gt;
&lt;br /&gt;
== Configuration of ArduCounter analog counters ==&lt;br /&gt;
&lt;br /&gt;
This module and the corresponding sketch can be used to read out old analog ferraris energy counters. Therefore an ESP, Arduino Uno or Nano board needs to be connected to a reflection light barrier which consists simply of an infra red photo transistor (connected to A7 on Arduinos and A0 on ESP8266) and an infra red led (connected to D2 on Arduinos and to D6 on ESP8266), both with a resistor in line. The idea comes from Martin Kompf (https://www.kompf.de/tech/emeir.html) and has been adopted for ArduCounter to support old ferraris energy counters.&lt;br /&gt;
&lt;br /&gt;
To support this mode, the sketch has to be compiled with analogIR defined.&lt;br /&gt;
&lt;br /&gt;
The configuration is then similar to the one for digital counters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define ACF ArduCounter /dev/ttyUSB4&lt;br /&gt;
attr ACF analogThresholds 100 110&lt;br /&gt;
attr ACF flashCommand avrdude -p atmega328P -b57600 -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2&amp;gt;[LOGFILE]&lt;br /&gt;
attr ACF interval 60 300 2 2&lt;br /&gt;
attr ACF pinA7 rising 20&lt;br /&gt;
attr ACF pulsesPerKWh 75&lt;br /&gt;
attr ACF stateFormat {sprintf(&amp;quot;%.3f kW&amp;quot;, ReadingsVal($name,&amp;quot;powerA7&amp;quot;,0))}&lt;br /&gt;
&amp;lt;/pre&amp;gt;        &lt;br /&gt;
&lt;br /&gt;
To find out the right analog thresholds you can set devVerbose to 20 which will ask the firmware of your conting board to report every analog measurement. The ArduCounter module will count how often each value is reported and you can then query these analog level counts with get levels. After a few turns of the ferraris disc the result of get levels might look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
observed levels from analog input:&lt;br /&gt;
94: 21&lt;br /&gt;
95: 79&lt;br /&gt;
96: 6&lt;br /&gt;
97: 2&lt;br /&gt;
98: 3&lt;br /&gt;
99: 2&lt;br /&gt;
100: 2&lt;br /&gt;
101: 1&lt;br /&gt;
102: 3&lt;br /&gt;
105: 2&lt;br /&gt;
106: 1&lt;br /&gt;
108: 2&lt;br /&gt;
109: 1&lt;br /&gt;
110: 1&lt;br /&gt;
112: 1&lt;br /&gt;
113: 3&lt;br /&gt;
115: 4&lt;br /&gt;
116: 9&lt;br /&gt;
117: 14&lt;br /&gt;
118: 71&lt;br /&gt;
119: 103&lt;br /&gt;
120: 118&lt;br /&gt;
121: 155&lt;br /&gt;
122: 159&lt;br /&gt;
123: 143&lt;br /&gt;
124: 147&lt;br /&gt;
125: 158&lt;br /&gt;
126: 198&lt;br /&gt;
127: 249&lt;br /&gt;
128: 220&lt;br /&gt;
129: 230&lt;br /&gt;
130: 201&lt;br /&gt;
131: 140&lt;br /&gt;
132: 147&lt;br /&gt;
133: 153&lt;br /&gt;
134: 141&lt;br /&gt;
135: 119&lt;br /&gt;
136: 105&lt;br /&gt;
137: 109&lt;br /&gt;
138: 114&lt;br /&gt;
139: 83&lt;br /&gt;
140: 33&lt;br /&gt;
141: 14&lt;br /&gt;
142: 1      &lt;br /&gt;
&amp;lt;/pre&amp;gt;      &lt;br /&gt;
  &lt;br /&gt;
This shows the measured values together with the frequency how often the individual value has been measured. It is obvious that most measurements result in values between 120 and 135, very few values are betweem 96 and 115 and another peak is around the value 95.&lt;br /&gt;
It means that the when the red mark of the ferraris disc is under the sensor, the value is around 95 and while the blank disc is under the sensor, the value is typically between 120 and 135. So a good upper threshold would be 120 and a good lower threshold would be for example 96.&lt;br /&gt;
&lt;br /&gt;
== Get-Commands ==&lt;br /&gt;
;info &lt;br /&gt;
:send a command to the Arduino board to get current counts. &lt;br /&gt;
:This is not needed for normal operation but might be useful sometimes for debugging.&lt;br /&gt;
&lt;br /&gt;
;levels&lt;br /&gt;
:show the count for the measured levels if an analog pin is used to measure e.g. the red mark of a ferraris counter disc. &lt;br /&gt;
:This is useful for setting the thresholds for analog measurements.&lt;br /&gt;
&lt;br /&gt;
;history&lt;br /&gt;
:shows details regarding all the level changes that the counter device (Arduino or ESP) has detected &lt;br /&gt;
:and how they were used (counted or rejected)&lt;br /&gt;
:If get history is issued with a pin name (e.g. get history D5) then only the history entries concerning D5 will be shown.&lt;br /&gt;
:This information is sent from the device to Fhem when it reports the current count but only if devVerbose is equal or greater than 5.&lt;br /&gt;
:The maximum number of lines that the Arducounter module stores in a ring buffer is defined by the attribute maxHist and defaults to 1000.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Set-Commands ==&lt;br /&gt;
&lt;br /&gt;
;raw&lt;br /&gt;
:send the value to the board so you can directly talk to the sketch using its commands.&lt;br /&gt;
:This is not needed for normal operation but might be useful sometimes for debugging&lt;br /&gt;
&lt;br /&gt;
;flash&lt;br /&gt;
:flashes the ArduCounter firmware ArduCounter.hex from the fhem subdirectory FHEM/firmware onto the device. &lt;br /&gt;
:This command needs avrdude to be installed. The attribute flashCommand specidies how avrdude is called. &lt;br /&gt;
:If it is not modifed then the module sets it to avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2&amp;gt;[LOGFILE]&lt;br /&gt;
:This setting should work for a standard installation and the placeholders are automatically replaced when the command is used. &lt;br /&gt;
:So normally there is no need to modify this attribute.&lt;br /&gt;
:Depending on your specific Arduino board however, you might need to insert -b 57600 in the flash Command. &lt;br /&gt;
:(e.g. for an Arduino Nano) ESP boards so far have to be flashed from the Arduino IDE. In a future version flashing over the air sould be supported.&lt;br /&gt;
&lt;br /&gt;
;reset&lt;br /&gt;
:reopens the arduino device and sends a command to it which causes a reinitialize and reset of the counters. Then the module resends the attribute configuration / definition of the pins to the device.&lt;br /&gt;
&lt;br /&gt;
;saveConfig&lt;br /&gt;
:stores the current interval, analog threshold and pin configuration to be stored in the EEPROM of the counter device &lt;br /&gt;
:so it can be retrieved after a reset.&lt;br /&gt;
&lt;br /&gt;
;enable&lt;br /&gt;
:sets the attribute disable to 0&lt;br /&gt;
&lt;br /&gt;
;disable&lt;br /&gt;
:sets the attribute disable to 1&lt;br /&gt;
&lt;br /&gt;
;reconnect&lt;br /&gt;
:closes the tcp connection to an ESP based counter board that is conected via TCP/IP and reopen the connection&lt;br /&gt;
&lt;br /&gt;
== Supported readings ==&lt;br /&gt;
The module creates at least the following readings and events for each defined pin:&lt;br /&gt;
&lt;br /&gt;
;pin.* e.g. pinD4&lt;br /&gt;
:the current internal count at this pin (internal to the Arduino / ESP device, starts at 0 when the device restarts).&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNameCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;long.* e.g. longD5&lt;br /&gt;
:long count which keeps on counting up after fhem restarts whereas the pin.* count is only a temporary internal count that starts at 0 when the arduino board starts.&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNameLongCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;interpolatedLong.*&lt;br /&gt;
:like long.* but when the Arduino restarts the potentially missed pulses are interpolated based on the pulse rate before the restart and after the restart.&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNameInterpolatedCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;calcCounter.*&lt;br /&gt;
:similar to long count which keeps on counting up after fhem restarts but this counter will take the pulses per kWh setting into the :calculation und thus not count pulses but real kWh (or some other unit that is applicable)&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNameCalcCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;reject.*&lt;br /&gt;
:counts rejected pulses that are shorter than the specified minimal pulse length.&lt;br /&gt;
&lt;br /&gt;
;power.*&lt;br /&gt;
:the current calculated power at this pin.&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNamePower[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;pinHistory.*&lt;br /&gt;
:shows detailed information of the last pulses. This is only available when a minimal pulse length is specified for this pin. Also the total number of impulses recorded here is limited to 20 for all pins together. The output looks like -36/7:0C, -29/7:1G, -22/8:0C, -14/7:1G, -7/7:0C, 0/7:1G&lt;br /&gt;
:The first number is the relative time in milliseconds when the input level changed, followed by the length in milliseconds, the level and the internal action. -36/7:0C for example means that 36 milliseconds before the reporting started, the input changed to 0V, stayed there for 7 milliseconds and this was counted.&lt;br /&gt;
&lt;br /&gt;
;countDiff.*&lt;br /&gt;
:delta of the current count to the last reported one. This is used together with timeDiff.* to calculate the power consumption.&lt;br /&gt;
&lt;br /&gt;
;timeDiff.*&lt;br /&gt;
:time difference between the first pulse in the current observation interval and the last one. Used togehter with countDiff to calculate the power consumption.&lt;br /&gt;
&lt;br /&gt;
;seq.*&lt;br /&gt;
:internal sequence number of the last report from the board to Fhem.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Attributes ==&lt;br /&gt;
&lt;br /&gt;
;do_not_notify&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
;pin.* &lt;br /&gt;
:Define a pin of the Arduino board as input. This attribute expects either &amp;lt;code&amp;gt;rising&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;falling&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;change&amp;lt;/code&amp;gt;, followed by an optional &amp;lt;code&amp;gt;pullup&amp;lt;/code&amp;gt; and an optional number as value.&lt;br /&gt;
:If a number is specified, the arduino will track rising and falling edges of each impulse and measure the length of a pulse in milliseconds. &lt;br /&gt;
:The number specified here is the minimal length of a pulse and a pause before a pulse. If one is too small, the pulse is not counted but added to a separate reject counter.&lt;br /&gt;
&lt;br /&gt;
;interval normal max min mincout &lt;br /&gt;
:Defines the parameters that affect the way counting and reporting works.&lt;br /&gt;
:This Attribute expects at least two and a maximum of four numbers as value. &lt;br /&gt;
: The first is the normal interval, the second the maximal interval, the third is a minimal interval and the fourth is a minimal pulse count.&lt;br /&gt;
&lt;br /&gt;
:In the usual operation mode (when the normal interval is smaller than the maximum interval), the Arduino board just counts and remembers the time between the first impulse and the last impulse for each pin.&lt;br /&gt;
:After the normal interval is elapsed the Arduino board reports the count and time for those pins where impulses were encountered.&lt;br /&gt;
:This means that even though the normal interval might be 10 seconds, the reported time difference can be something different because it observed impulses as starting and ending point.&lt;br /&gt;
:The Power (e.g. for energy meters) is the calculated based of the counted impulses and the time between the first and the last impulse. &lt;br /&gt;
:For the next interval, the starting time will be the time of the last impulse in the previous reporting period and the time difference will be taken up to the last impulse before the reporting interval has elapsed.&lt;br /&gt;
&lt;br /&gt;
:The second, third and fourth numbers (maximum, minimal interval and minimal count) exist for the special case when the pulse frequency is very low and the reporting time is comparatively short.&lt;br /&gt;
:For example if the normal interval (first number) is 60 seconds and the device counts only one impulse in 90 seconds, the the calculated power reading will jump up and down and will give ugly numbers.&lt;br /&gt;
:By adjusting the other numbers of this attribute this can be avoided.&lt;br /&gt;
:In case in the normal interval the observed impulses are encountered in a time difference that is smaller than the third number (minimal interval) or if the number of impulses counted is smaller than the fourth number (minimal count) then the reporting is delayed until the maximum interval has elapsed or the above conditions have changed after another normal interval.&lt;br /&gt;
:This way the counter will report a higher number of pulses counted and a larger time difference back to fhem.&lt;br /&gt;
&lt;br /&gt;
:If this is seems too complicated and you prefer a simple and constant reporting interval, then you can set the normal interval and the mximum interval to the same number. This changes the operation mode of the counter to just count during this normal and maximum interval and report the count. In this case the reported time difference is always the reporting interval and not the measured time between the real impulses.&lt;br /&gt;
&lt;br /&gt;
;factor &lt;br /&gt;
:Define a multiplicator for calculating the power from the impulse count and the time between the first and the last impulse.&lt;br /&gt;
:This attribute is outdated and unintuitive so you should avoid it.&lt;br /&gt;
:Instead you should specify the attribute pulsesPerKWh or readingPulsesPerKWh[0-9]+ (where [0-9]+ stands for the pin number).&lt;br /&gt;
&lt;br /&gt;
;readingFactor[0-9]+&lt;br /&gt;
:Override the factor attribute for this individual pin.&lt;br /&gt;
:Just like the attribute factor, this is a rather cumbersome way to specify the pulses per kWh.&lt;br /&gt;
:Instaed it is advised to use the attribute pulsesPerKWh or readingPulsesPerKWh[0-9]+ (where [0-9]+ stands for the pin number).&lt;br /&gt;
&lt;br /&gt;
;pulsesPerKWh&lt;br /&gt;
:specify the number of pulses that the meter is giving out per unit that sould be displayed (e.g. per kWh energy consumed). For many S0 counters this is 1000, for old ferraris counters this is 75 (rounds per kWh).&lt;br /&gt;
:Example: attr myCounter pulsesPerKWh 75&lt;br /&gt;
&lt;br /&gt;
;readingPulsesPerKWh[0-9]+&lt;br /&gt;
:is the same as pulsesPerKWh but specified per pin individually in case you have multiple counters with different settings at the same time&lt;br /&gt;
:Example:&lt;br /&gt;
:attr myCounter readingPulsesPerKWhA7 75&lt;br /&gt;
:attr myCounter readingPulsesPerKWhD4 1000&lt;br /&gt;
&lt;br /&gt;
;readingNameCount[0-9]+ &lt;br /&gt;
:Change the name of the counter reading pinX to something more meaningful.&lt;br /&gt;
&lt;br /&gt;
;readingNameLongCount[0-9]+ &lt;br /&gt;
:Change the name of the counter reading longX to something more meaningful.&lt;br /&gt;
&lt;br /&gt;
;readingNameInterpolatedCount[0-9]+ &lt;br /&gt;
:Change the name of the counter reading InterpolatedLongX to something more meaningful.&lt;br /&gt;
&lt;br /&gt;
;readingNameCalcCount[AD]?[0-9]+&lt;br /&gt;
:Change the name of the real unit counter reading CalcCounterX to something more meaningful.&lt;br /&gt;
:Example: attr myCounter readingNameCalcCountD4 CounterHaus_kWh&lt;br /&gt;
&lt;br /&gt;
;readingNamePower[0-9]+ &lt;br /&gt;
:Change the name of the power reading powerX to something more meaningful.&lt;br /&gt;
&lt;br /&gt;
;readingStartTime[0-9]+ &lt;br /&gt;
:Allow the reading time stamp to be set to the beginning of measuring intervals&lt;br /&gt;
&lt;br /&gt;
;verboseReadings[0-9]+ &lt;br /&gt;
:create additional readings: timeDiff, countDiff and lastMsg for each pin&lt;br /&gt;
&lt;br /&gt;
;devVerbose&lt;br /&gt;
:set the verbose level in the counting board. This defaults to 0.&lt;br /&gt;
:If the value is &amp;gt;0, then the firmware will echo all commands sent to it by the Fhem module.&lt;br /&gt;
:If the value is &amp;gt;=5, then the firmware will report the pin history (assuming that the firmware has been compiled with this feature enabled)&lt;br /&gt;
:If the value is &amp;gt;=10, then the firmware will report every level change of a pin&lt;br /&gt;
:If the value is &amp;gt;=20, then the firmware will report every analog measurement (assuming that the firmware has been compiled with analog measurements for old ferraris counters or similar).&lt;br /&gt;
&lt;br /&gt;
;maxHist&lt;br /&gt;
:specifies how many pin history lines hould be buffered for &amp;quot;get history&amp;quot;.&lt;br /&gt;
:This attribute defaults to 1000.&lt;br /&gt;
&lt;br /&gt;
;analogThresholds&lt;br /&gt;
:this Attribute is necessary when you use an arduino nano with connected reflection light barrier (photo transistor and led) to detect the red mark of an old ferraris energy counter. In this case the firmware uses an upper and lower threshold which can be set here.&lt;br /&gt;
:Example: attr myCounter analogThresholds 90 110&lt;br /&gt;
:In order to find out the right threshold values you can set devVerbose to 20, wait for several turns of the ferraris disc and then use get levels to see the typical measurements for the red mark and the blank disc.&lt;br /&gt;
&lt;br /&gt;
;flashCommand&lt;br /&gt;
:sets the command to call avrdude and flash the onnected arduino with an updated hex file (by default it looks for ArduCounter.hex in the FHEM/firmware subdirectory.&lt;br /&gt;
:This attribute contains avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2&amp;gt;[LOGFILE] by default.&lt;br /&gt;
:For an Arduino Nano based counter you should add -b 57600 e.g. between the -P and -D options.&lt;br /&gt;
:Example: attr myCounter flashCommand avrdude -p atmega328P -c arduino -b 57600 -P [PORT] -D -U flash:w:[HEXFILE] 2&amp;gt;[LOGFILE]&lt;br /&gt;
&lt;br /&gt;
;keepAliveDelay&lt;br /&gt;
:defines an interval in which the module sends keepalive messages to a counter device that is conected via tcp.&lt;br /&gt;
:This attribute is ignored if the device is connected via serial port.&lt;br /&gt;
:If the device doesn&#039;t reply within a defined timeout then the module closes and tries to reopen the connection.&lt;br /&gt;
:The module tells the device when to expect the next keepalive message and the device will also close the tcp connection if it doesn&#039;t see a :keepalive message within the delay multiplied by 3&lt;br /&gt;
:The delay defaults to 10 seconds.&lt;br /&gt;
:Example: attr myCounter keepAliveDelay 30&lt;br /&gt;
&lt;br /&gt;
;keepAliveTimeout&lt;br /&gt;
:defines the timeout when wainting for a keealive reply (see keepAliveDelay) The timeout defaults to 2 seconds.&lt;br /&gt;
:Example: attr myCounter keepAliveTimeout 3&lt;br /&gt;
&lt;br /&gt;
;keepAliveRetries&lt;br /&gt;
:defines how often sending a keepalive is retried before the connection is closed and reopened.&lt;br /&gt;
:It defaults to 2.&lt;br /&gt;
:Example: attr myCounter keepAliveRetries 3&lt;br /&gt;
&lt;br /&gt;
;nextOpenDelay&lt;br /&gt;
:defines the time that the module waits before retrying to open a disconnected tcp connection.&lt;br /&gt;
:This defaults to 60 seconds.&lt;br /&gt;
:Example: attr myCounter nextOpenDelay 20&lt;br /&gt;
&lt;br /&gt;
;openTimeout&lt;br /&gt;
:defines the timeout after which tcp open gives up trying to establish a connection to the counter device. This timeout defaults to 3 seconds.&lt;br /&gt;
:Example: attr myCounter openTimeout 5&lt;br /&gt;
&lt;br /&gt;
;silentReconnect&lt;br /&gt;
:if set to 1, then it will set the loglevel for &amp;quot;disconnected&amp;quot; and &amp;quot;reappeared&amp;quot; messages to 4 instead of 3&lt;br /&gt;
:Example: attr myCounter silentReconnect 1&lt;br /&gt;
&lt;br /&gt;
;disable&lt;br /&gt;
:if set to 1 then the module closes the connection to a counter device.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Other Components]]&lt;br /&gt;
[[Kategorie:Energieverbrauchsmessung]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=ArduCounter&amp;diff=32258</id>
		<title>ArduCounter</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=ArduCounter&amp;diff=32258"/>
		<updated>2020-01-01T22:54:47Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Prerequisites */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Modul&lt;br /&gt;
|ModPurpose=Count pulses, calculate time between pulses and convert this to readings for e.g. power consumption of Energy meters&lt;br /&gt;
|ModType=contrib&lt;br /&gt;
|ModCmdRef=ArduCounter&lt;br /&gt;
|ModForumArea=Sonstiges&lt;br /&gt;
|ModFTopic=19285&lt;br /&gt;
|ModTechName=98_ArduCounter.pm&lt;br /&gt;
|ModOwner=StefanStrobel ({{Link2FU|3960|Forum}} / [[Benutzer:StefanStrobel|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
This module implements an Interface to an Arduino or ESP8266 based counter for pulses on any input pin of an Arduino Uno, Nano, Jeenode, NodeMCU, Wemos D1 or similar device. The device connects to FHEM either through USB / serial or via tcp if an ESP board is used.&lt;br /&gt;
&lt;br /&gt;
The typical use case is an S0-Interface on an energy meter or water meter, but also reflection light barriers to monitor old ferraris counters are supported&lt;br /&gt;
&lt;br /&gt;
Counters are configured with attributes that define which Arduino pins should count pulses and in which intervals the Arduino board should report the current counts.&lt;br /&gt;
&lt;br /&gt;
The Arduino sketch that works with this module uses pin change interrupts so it can efficiently count pulses on all available input pins.&lt;br /&gt;
The module creates readings for pulse counts, consumption and optionally also a pin history with pulse lengths and gaps of the last pulses.&lt;br /&gt;
&lt;br /&gt;
== Availability == &lt;br /&gt;
The module has been checked in to the FHEM svn. &lt;br /&gt;
The corresponding Arduino sketch can also be found under contrib in the subdirectory arduino/.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
This module requires an Arduino Uno, Nano, Jeenode, NodeMCU, Wemos D1 or similar device based on an Atmel 328p or ESP8266 running the ArduCounter sketch provided with this module&lt;br /&gt;
&lt;br /&gt;
In order to flash an Arduino board with the corresponding ArduCounter firmware from within Fhem, avrdude needs to be installed.&lt;br /&gt;
&lt;br /&gt;
For old ferraris counters an Arduino Uno or Nano or ESP8266 board needs to be connected to a reflection light barrier which consists simply of an infra red photo transistor (connected to A7 on Arduinos and A0 on ESP8266) and an infra red led (connected to D2 on Arduinos and to D6 on ESP8266), both with a resistor in line.&lt;br /&gt;
&lt;br /&gt;
This module also requires Device::SerialPort or Win32::SerialPort for communication via serial lines&lt;br /&gt;
&lt;br /&gt;
== Define ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;define &amp;lt;name&amp;gt; ArduCounter &amp;lt;device&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
&amp;lt;pre&amp;gt;define &amp;lt;name&amp;gt; ArduCounter &amp;lt;ip:port&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;device&amp;gt; specifies the serial port to communicate with the Arduino.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ip:port&amp;gt; specifies the ip address and tcp port to communicate with an esp8266 where port is typically 80.&lt;br /&gt;
&lt;br /&gt;
The name of the serial-device depends on your distribution. You can also specify a baudrate for serial connections if the device name contains the @ character, e.g.: /dev/ttyUSB0@38400. The default baudrate of the ArduCounter firmware is 38400 since Version 1.4&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define AC ArduCounter /dev/ttyUSB2@38400&lt;br /&gt;
define AC ArduCounter 192.168.1.134:80&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configuration of ArduCounter digital counters ==&lt;br /&gt;
&lt;br /&gt;
Specify the pins where impulses should be counted e.g. as attr AC pinX falling pullup 30&lt;br /&gt;
&lt;br /&gt;
The X in pinX can be an Arduino / ESP pin number with or without the letter D e.g. pin4, pinD5, pin6, pinD7 ...&lt;br /&gt;
&lt;br /&gt;
After the pin you can use the keywords falling or rising to define if a logical one / 5V (rising) or a logical zero / 0V (falling) should be treated as pulse.&lt;br /&gt;
&lt;br /&gt;
The optional keyword pullup activates the pullup resistor for the given Pin.&lt;br /&gt;
&lt;br /&gt;
The last argument is also optional but recommended and specifies a minimal pulse length in milliseconds.&lt;br /&gt;
&lt;br /&gt;
An energy meter with S0 interface is typically connected to GND and an input pin like D4.&lt;br /&gt;
The S0 pulse then pulls the input to 0V.&lt;br /&gt;
Since the minimal pulse lenght of the s0 interface is specified to be 30ms, the typical configuration for an s0 interface is&lt;br /&gt;
attr AC pinX falling pullup 30&lt;br /&gt;
&lt;br /&gt;
Specifying a minimal pulse length is recommended since it filters bouncing of reed contacts or other noise.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define AC ArduCounter /dev/ttyUSB2&lt;br /&gt;
attr AC pulsesPerKWh 1000&lt;br /&gt;
attr AC interval 60 300&lt;br /&gt;
attr AC pinD4 falling pullup 5&lt;br /&gt;
attr AC pinD5 falling pullup 30&lt;br /&gt;
attr AC verboseReadingsD5&lt;br /&gt;
attr AC pinD6 rising&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
This defines three counters connected to the pins D4, D5 and D5.&lt;br /&gt;
D4 and D5 have their pullup resistors activated and the impulse draws the pins to zero.&lt;br /&gt;
For D4 and D5 the arduino measures the time in milliseconds between the falling edge and the rising edge. If this time is longer than the specified 5 or 30 milliseconds then the impulse is counted.&lt;br /&gt;
If the time is shorter then this impulse is regarded as noise and added to a separate reject counter.&lt;br /&gt;
&lt;br /&gt;
verboseReadings5 causes the module to create additional readings like the pin history which shows length and gaps between the last pulses.&lt;br /&gt;
&lt;br /&gt;
For pin D6 the arduino does not check pulse lengths and counts every time when the signal changes from 0 to 1.&lt;br /&gt;
&lt;br /&gt;
The ArduCounter sketch which must be loaded on the Arduino or ESP implements this using pin change interrupts, so all avilable input pins can be used, not only the ones that support normal interrupts.&lt;br /&gt;
The module has been tested with 14 inputs of an Arduino Uno counting in parallel and pulses as short as 3 milliseconds.&lt;br /&gt;
&lt;br /&gt;
== Configuration of ArduCounter analog counters ==&lt;br /&gt;
&lt;br /&gt;
This module and the corresponding sketch can be used to read out old analog ferraris energy counters. Therefore an ESP, Arduino Uno or Nano board needs to be connected to a reflection light barrier which consists simply of an infra red photo transistor (connected to A7 on Arduinos and A0 on ESP8266) and an infra red led (connected to D2 on Arduinos and to D6 on ESP8266), both with a resistor in line. The idea comes from Martin Kompf (https://www.kompf.de/tech/emeir.html) and has been adopted for ArduCounter to support old ferraris energy counters.&lt;br /&gt;
&lt;br /&gt;
To support this mode, the sketch has to be compiled with analogIR defined.&lt;br /&gt;
&lt;br /&gt;
The configuration is then similar to the one for digital counters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define ACF ArduCounter /dev/ttyUSB4&lt;br /&gt;
attr ACF analogThresholds 100 110&lt;br /&gt;
attr ACF flashCommand avrdude -p atmega328P -b57600 -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2&amp;gt;[LOGFILE]&lt;br /&gt;
attr ACF interval 60 300 2 2&lt;br /&gt;
attr ACF pinA7 rising 20&lt;br /&gt;
attr ACF pulsesPerKWh 75&lt;br /&gt;
attr ACF stateFormat {sprintf(&amp;quot;%.3f kW&amp;quot;, ReadingsVal($name,&amp;quot;powerA7&amp;quot;,0))}&lt;br /&gt;
&amp;lt;/pre&amp;gt;        &lt;br /&gt;
&lt;br /&gt;
To find out the right analog thresholds you can set devVerbose to 20 which will ask the firmware of your conting board to report every analog measurement. The ArduCounter module will count how often each value is reported and you can then query these analog level counts with get levels. After a few turns of the ferraris disc the result of get levels might look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
observed levels from analog input:&lt;br /&gt;
94: 21&lt;br /&gt;
95: 79&lt;br /&gt;
96: 6&lt;br /&gt;
97: 2&lt;br /&gt;
98: 3&lt;br /&gt;
99: 2&lt;br /&gt;
100: 2&lt;br /&gt;
101: 1&lt;br /&gt;
102: 3&lt;br /&gt;
105: 2&lt;br /&gt;
106: 1&lt;br /&gt;
108: 2&lt;br /&gt;
109: 1&lt;br /&gt;
110: 1&lt;br /&gt;
112: 1&lt;br /&gt;
113: 3&lt;br /&gt;
115: 4&lt;br /&gt;
116: 9&lt;br /&gt;
117: 14&lt;br /&gt;
118: 71&lt;br /&gt;
119: 103&lt;br /&gt;
120: 118&lt;br /&gt;
121: 155&lt;br /&gt;
122: 159&lt;br /&gt;
123: 143&lt;br /&gt;
124: 147&lt;br /&gt;
125: 158&lt;br /&gt;
126: 198&lt;br /&gt;
127: 249&lt;br /&gt;
128: 220&lt;br /&gt;
129: 230&lt;br /&gt;
130: 201&lt;br /&gt;
131: 140&lt;br /&gt;
132: 147&lt;br /&gt;
133: 153&lt;br /&gt;
134: 141&lt;br /&gt;
135: 119&lt;br /&gt;
136: 105&lt;br /&gt;
137: 109&lt;br /&gt;
138: 114&lt;br /&gt;
139: 83&lt;br /&gt;
140: 33&lt;br /&gt;
141: 14&lt;br /&gt;
142: 1      &lt;br /&gt;
&amp;lt;/pre&amp;gt;      &lt;br /&gt;
  &lt;br /&gt;
This shows the measured values together with the frequency how often the individual value has been measured. It is obvious that most measurements result in values between 120 and 135, very few values are betweem 96 and 115 and another peak is around the value 95.&lt;br /&gt;
It means that the when the red mark of the ferraris disc is under the sensor, the value is around 95 and while the blank disc is under the sensor, the value is typically between 120 and 135. So a good upper threshold would be 120 and a good lower threshold would be for example 96.&lt;br /&gt;
&lt;br /&gt;
== Get-Commands ==&lt;br /&gt;
;info &lt;br /&gt;
:send a command to the Arduino board to get current counts. &lt;br /&gt;
:This is not needed for normal operation but might be useful sometimes for debugging.&lt;br /&gt;
&lt;br /&gt;
;levels&lt;br /&gt;
:show the count for the measured levels if an analog pin is used to measure e.g. the red mark of a ferraris counter disc. &lt;br /&gt;
:This is useful for setting the thresholds for analog measurements.&lt;br /&gt;
&lt;br /&gt;
;history&lt;br /&gt;
:shows details regarding all the level changes that the counter device (Arduino or ESP) has detected &lt;br /&gt;
:and how they were used (counted or rejected)&lt;br /&gt;
:If get history is issued with a pin name (e.g. get history D5) then only the history entries concerning D5 will be shown.&lt;br /&gt;
:This information is sent from the device to Fhem when it reports the current count but only if devVerbose is equal or greater than 5.&lt;br /&gt;
:The maximum number of lines that the Arducounter module stores in a ring buffer is defined by the attribute maxHist and defaults to 1000.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Set-Commands ==&lt;br /&gt;
&lt;br /&gt;
;raw&lt;br /&gt;
:send the value to the board so you can directly talk to the sketch using its commands.&lt;br /&gt;
:This is not needed for normal operation but might be useful sometimes for debugging&lt;br /&gt;
&lt;br /&gt;
;flash&lt;br /&gt;
:flashes the ArduCounter firmware ArduCounter.hex from the fhem subdirectory FHEM/firmware onto the device. &lt;br /&gt;
:This command needs avrdude to be installed. The attribute flashCommand specidies how avrdude is called. &lt;br /&gt;
:If it is not modifed then the module sets it to avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2&amp;gt;[LOGFILE]&lt;br /&gt;
:This setting should work for a standard installation and the placeholders are automatically replaced when the command is used. &lt;br /&gt;
:So normally there is no need to modify this attribute.&lt;br /&gt;
:Depending on your specific Arduino board however, you might need to insert -b 57600 in the flash Command. &lt;br /&gt;
:(e.g. for an Arduino Nano) ESP boards so far have to be fashed from the Arduino IDE. In a future version flashing over the air sould be supported.&lt;br /&gt;
&lt;br /&gt;
;reset&lt;br /&gt;
:reopens the arduino device and sends a command to it which causes a reinitialize and reset of the counters. Then the module resends the attribute configuration / definition of the pins to the device.&lt;br /&gt;
&lt;br /&gt;
;saveConfig&lt;br /&gt;
:stores the current interval, analog threshold and pin configuration to be stored in the EEPROM of the counter device &lt;br /&gt;
:so it can be retrieved after a reset.&lt;br /&gt;
&lt;br /&gt;
;enable&lt;br /&gt;
:sets the attribute disable to 0&lt;br /&gt;
&lt;br /&gt;
;disable&lt;br /&gt;
:sets the attribute disable to 1&lt;br /&gt;
&lt;br /&gt;
;reconnect&lt;br /&gt;
:closes the tcp connection to an ESP based counter board that is conected via TCP/IP and reopen the connection&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Supported readings ==&lt;br /&gt;
The module creates at least the following readings and events for each defined pin:&lt;br /&gt;
&lt;br /&gt;
;pin.* e.g. pinD4&lt;br /&gt;
:the current internal count at this pin (internal to the Arduino / ESP device, starts at 0 when the device restarts).&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNameCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;long.* e.g. longD5&lt;br /&gt;
:long count which keeps on counting up after fhem restarts whereas the pin.* count is only a temporary internal count that starts at 0 when the arduino board starts.&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNameLongCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;interpolatedLong.*&lt;br /&gt;
:like long.* but when the Arduino restarts the potentially missed pulses are interpolated based on the pulse rate before the restart and after the restart.&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNameInterpolatedCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;calcCounter.*&lt;br /&gt;
:similar to long count which keeps on counting up after fhem restarts but this counter will take the pulses per kWh setting into the :calculation und thus not count pulses but real kWh (or some other unit that is applicable)&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNameCalcCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;reject.*&lt;br /&gt;
:counts rejected pulses that are shorter than the specified minimal pulse length.&lt;br /&gt;
&lt;br /&gt;
;power.*&lt;br /&gt;
:the current calculated power at this pin.&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNamePower[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;pinHistory.*&lt;br /&gt;
:shows detailed information of the last pulses. This is only available when a minimal pulse length is specified for this pin. Also the total number of impulses recorded here is limited to 20 for all pins together. The output looks like -36/7:0C, -29/7:1G, -22/8:0C, -14/7:1G, -7/7:0C, 0/7:1G&lt;br /&gt;
:The first number is the relative time in milliseconds when the input level changed, followed by the length in milliseconds, the level and the internal action. -36/7:0C for example means that 36 milliseconds before the reporting started, the input changed to 0V, stayed there for 7 milliseconds and this was counted.&lt;br /&gt;
&lt;br /&gt;
;countDiff.*&lt;br /&gt;
:delta of the current count to the last reported one. This is used together with timeDiff.* to calculate the power consumption.&lt;br /&gt;
&lt;br /&gt;
;timeDiff.*&lt;br /&gt;
:time difference between the first pulse in the current observation interval and the last one. Used togehter with countDiff to calculate the power consumption.&lt;br /&gt;
&lt;br /&gt;
;seq.*&lt;br /&gt;
:internal sequence number of the last report from the board to Fhem.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Attributes ==&lt;br /&gt;
&lt;br /&gt;
;do_not_notify&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
;pin.* &lt;br /&gt;
:Define a pin of the Arduino board as input. This attribute expects either &amp;lt;code&amp;gt;rising&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;falling&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;change&amp;lt;/code&amp;gt;, followed by an optional &amp;lt;code&amp;gt;pullup&amp;lt;/code&amp;gt; and an optional number as value.&lt;br /&gt;
:If a number is specified, the arduino will track rising and falling edges of each impulse and measure the length of a pulse in milliseconds. &lt;br /&gt;
:The number specified here is the minimal length of a pulse and a pause before a pulse. If one is too small, the pulse is not counted but added to a separate reject counter.&lt;br /&gt;
&lt;br /&gt;
;interval normal max min mincout &lt;br /&gt;
:Defines the parameters that affect the way counting and reporting works.&lt;br /&gt;
:This Attribute expects at least two and a maximum of four numbers as value. &lt;br /&gt;
: The first is the normal interval, the second the maximal interval, the third is a minimal interval and the fourth is a minimal pulse count.&lt;br /&gt;
&lt;br /&gt;
:In the usual operation mode (when the normal interval is smaller than the maximum interval), the Arduino board just counts and remembers the time between the first impulse and the last impulse for each pin.&lt;br /&gt;
:After the normal interval is elapsed the Arduino board reports the count and time for those pins where impulses were encountered.&lt;br /&gt;
:This means that even though the normal interval might be 10 seconds, the reported time difference can be something different because it observed impulses as starting and ending point.&lt;br /&gt;
:The Power (e.g. for energy meters) is the calculated based of the counted impulses and the time between the first and the last impulse. &lt;br /&gt;
:For the next interval, the starting time will be the time of the last impulse in the previous reporting period and the time difference will be taken up to the last impulse before the reporting interval has elapsed.&lt;br /&gt;
&lt;br /&gt;
:The second, third and fourth numbers (maximum, minimal interval and minimal count) exist for the special case when the pulse frequency is very low and the reporting time is comparatively short.&lt;br /&gt;
:For example if the normal interval (first number) is 60 seconds and the device counts only one impulse in 90 seconds, the the calculated power reading will jump up and down and will give ugly numbers.&lt;br /&gt;
:By adjusting the other numbers of this attribute this can be avoided.&lt;br /&gt;
:In case in the normal interval the observed impulses are encountered in a time difference that is smaller than the third number (minimal interval) or if the number of impulses counted is smaller than the fourth number (minimal count) then the reporting is delayed until the maximum interval has elapsed or the above conditions have changed after another normal interval.&lt;br /&gt;
:This way the counter will report a higher number of pulses counted and a larger time difference back to fhem.&lt;br /&gt;
&lt;br /&gt;
:If this is seems too complicated and you prefer a simple and constant reporting interval, then you can set the normal interval and the mximum interval to the same number. This changes the operation mode of the counter to just count during this normal and maximum interval and report the count. In this case the reported time difference is always the reporting interval and not the measured time between the real impulses.&lt;br /&gt;
&lt;br /&gt;
;factor &lt;br /&gt;
:Define a multiplicator for calculating the power from the impulse count and the time between the first and the last impulse.&lt;br /&gt;
:This attribute is outdated and unintuitive so you should avoid it.&lt;br /&gt;
:Instead you should specify the attribute pulsesPerKWh or readingPulsesPerKWh[0-9]+ (where [0-9]+ stands for the pin number).&lt;br /&gt;
&lt;br /&gt;
;readingFactor[0-9]+&lt;br /&gt;
:Override the factor attribute for this individual pin.&lt;br /&gt;
:Just like the attribute factor, this is a rather cumbersome way to specify the pulses per kWh.&lt;br /&gt;
:Instaed it is advised to use the attribute pulsesPerKWh or readingPulsesPerKWh[0-9]+ (where [0-9]+ stands for the pin number).&lt;br /&gt;
&lt;br /&gt;
;pulsesPerKWh&lt;br /&gt;
:specify the number of pulses that the meter is giving out per unit that sould be displayed (e.g. per kWh energy consumed). For many S0 counters this is 1000, for old ferraris counters this is 75 (rounds per kWh).&lt;br /&gt;
:Example: attr myCounter pulsesPerKWh 75&lt;br /&gt;
&lt;br /&gt;
;readingPulsesPerKWh[0-9]+&lt;br /&gt;
:is the same as pulsesPerKWh but specified per pin individually in case you have multiple counters with different settings at the same time&lt;br /&gt;
:Example:&lt;br /&gt;
:attr myCounter readingPulsesPerKWhA7 75&lt;br /&gt;
:attr myCounter readingPulsesPerKWhD4 1000&lt;br /&gt;
&lt;br /&gt;
;readingNameCount[0-9]+ &lt;br /&gt;
:Change the name of the counter reading pinX to something more meaningful.&lt;br /&gt;
&lt;br /&gt;
;readingNameLongCount[0-9]+ &lt;br /&gt;
:Change the name of the counter reading longX to something more meaningful.&lt;br /&gt;
&lt;br /&gt;
;readingNameInterpolatedCount[0-9]+ &lt;br /&gt;
:Change the name of the counter reading InterpolatedLongX to something more meaningful.&lt;br /&gt;
&lt;br /&gt;
;readingNameCalcCount[AD]?[0-9]+&lt;br /&gt;
:Change the name of the real unit counter reading CalcCounterX to something more meaningful.&lt;br /&gt;
:Example: attr myCounter readingNameCalcCountD4 CounterHaus_kWh&lt;br /&gt;
&lt;br /&gt;
;readingNamePower[0-9]+ &lt;br /&gt;
:Change the name of the power reading powerX to something more meaningful.&lt;br /&gt;
&lt;br /&gt;
;readingStartTime[0-9]+ &lt;br /&gt;
:Allow the reading time stamp to be set to the beginning of measuring intervals&lt;br /&gt;
&lt;br /&gt;
;verboseReadings[0-9]+ &lt;br /&gt;
:create additional readings: timeDiff, countDiff and lastMsg for each pin&lt;br /&gt;
&lt;br /&gt;
;devVerbose&lt;br /&gt;
:set the verbose level in the counting board. This defaults to 0.&lt;br /&gt;
:If the value is &amp;gt;0, then the firmware will echo all commands sent to it by the Fhem module.&lt;br /&gt;
:If the value is &amp;gt;=5, then the firmware will report the pin history (assuming that the firmware has been compiled with this feature enabled)&lt;br /&gt;
:If the value is &amp;gt;=10, then the firmware will report every level change of a pin&lt;br /&gt;
:If the value is &amp;gt;=20, then the firmware will report every analog measurement (assuming that the firmware has been compiled with analog measurements for old ferraris counters or similar).&lt;br /&gt;
&lt;br /&gt;
;maxHist&lt;br /&gt;
:specifies how many pin history lines hould be buffered for &amp;quot;get history&amp;quot;.&lt;br /&gt;
:This attribute defaults to 1000.&lt;br /&gt;
&lt;br /&gt;
;analogThresholds&lt;br /&gt;
:this Attribute is necessary when you use an arduino nano with connected reflection light barrier (photo transistor and led) to detect the red mark of an old ferraris energy counter. In this case the firmware uses an upper and lower threshold which can be set here.&lt;br /&gt;
:Example: attr myCounter analogThresholds 90 110&lt;br /&gt;
:In order to find out the right threshold values you can set devVerbose to 20, wait for several turns of the ferraris disc and then use get levels to see the typical measurements for the red mark and the blank disc.&lt;br /&gt;
&lt;br /&gt;
;flashCommand&lt;br /&gt;
:sets the command to call avrdude and flash the onnected arduino with an updated hex file (by default it looks for ArduCounter.hex in the FHEM/firmware subdirectory.&lt;br /&gt;
:This attribute contains avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2&amp;gt;[LOGFILE] by default.&lt;br /&gt;
:For an Arduino Nano based counter you should add -b 57600 e.g. between the -P and -D options.&lt;br /&gt;
:Example: attr myCounter flashCommand avrdude -p atmega328P -c arduino -b 57600 -P [PORT] -D -U flash:w:[HEXFILE] 2&amp;gt;[LOGFILE]&lt;br /&gt;
&lt;br /&gt;
;keepAliveDelay&lt;br /&gt;
:defines an interval in which the module sends keepalive messages to a counter device that is conected via tcp.&lt;br /&gt;
:This attribute is ignored if the device is connected via serial port.&lt;br /&gt;
:If the device doesn&#039;t reply within a defined timeout then the module closes and tries to reopen the connection.&lt;br /&gt;
:The module tells the device when to expect the next keepalive message and the device will also close the tcp connection if it doesn&#039;t see a :keepalive message within the delay multiplied by 3&lt;br /&gt;
:The delay defaults to 10 seconds.&lt;br /&gt;
:Example: attr myCounter keepAliveDelay 30&lt;br /&gt;
&lt;br /&gt;
;keepAliveTimeout&lt;br /&gt;
:defines the timeout when wainting for a keealive reply (see keepAliveDelay) The timeout defaults to 2 seconds.&lt;br /&gt;
:Example: attr myCounter keepAliveTimeout 3&lt;br /&gt;
&lt;br /&gt;
;keepAliveRetries&lt;br /&gt;
:defines how often sending a keepalive is retried before the connection is closed and reopened.&lt;br /&gt;
:It defaults to 2.&lt;br /&gt;
:Example: attr myCounter keepAliveRetries 3&lt;br /&gt;
&lt;br /&gt;
;nextOpenDelay&lt;br /&gt;
:defines the time that the module waits before retrying to open a disconnected tcp connection.&lt;br /&gt;
:This defaults to 60 seconds.&lt;br /&gt;
:Example: attr myCounter nextOpenDelay 20&lt;br /&gt;
&lt;br /&gt;
;openTimeout&lt;br /&gt;
:defines the timeout after which tcp open gives up trying to establish a connection to the counter device. This timeout defaults to 3 seconds.&lt;br /&gt;
:Example: attr myCounter openTimeout 5&lt;br /&gt;
&lt;br /&gt;
;silentReconnect&lt;br /&gt;
:if set to 1, then it will set the loglevel for &amp;quot;disconnected&amp;quot; and &amp;quot;reappeared&amp;quot; messages to 4 instead of 3&lt;br /&gt;
:Example: attr myCounter silentReconnect 1&lt;br /&gt;
&lt;br /&gt;
;disable&lt;br /&gt;
:if set to 1 then the module closes the connection to a counter device.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Other Components]]&lt;br /&gt;
[[Kategorie:Energieverbrauchsmessung]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=ArduCounter&amp;diff=32257</id>
		<title>ArduCounter</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=ArduCounter&amp;diff=32257"/>
		<updated>2020-01-01T22:54:15Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Availability */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Modul&lt;br /&gt;
|ModPurpose=Count pulses, calculate time between pulses and convert this to readings for e.g. power consumption of Energy meters&lt;br /&gt;
|ModType=contrib&lt;br /&gt;
|ModCmdRef=ArduCounter&lt;br /&gt;
|ModForumArea=Sonstiges&lt;br /&gt;
|ModFTopic=19285&lt;br /&gt;
|ModTechName=98_ArduCounter.pm&lt;br /&gt;
|ModOwner=StefanStrobel ({{Link2FU|3960|Forum}} / [[Benutzer:StefanStrobel|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
This module implements an Interface to an Arduino or ESP8266 based counter for pulses on any input pin of an Arduino Uno, Nano, Jeenode, NodeMCU, Wemos D1 or similar device. The device connects to FHEM either through USB / serial or via tcp if an ESP board is used.&lt;br /&gt;
&lt;br /&gt;
The typical use case is an S0-Interface on an energy meter or water meter, but also reflection light barriers to monitor old ferraris counters are supported&lt;br /&gt;
&lt;br /&gt;
Counters are configured with attributes that define which Arduino pins should count pulses and in which intervals the Arduino board should report the current counts.&lt;br /&gt;
&lt;br /&gt;
The Arduino sketch that works with this module uses pin change interrupts so it can efficiently count pulses on all available input pins.&lt;br /&gt;
The module creates readings for pulse counts, consumption and optionally also a pin history with pulse lengths and gaps of the last pulses.&lt;br /&gt;
&lt;br /&gt;
== Availability == &lt;br /&gt;
The module has been checked in to the FHEM svn. &lt;br /&gt;
The corresponding Arduino sketch can also be found under contrib in the subdirectory arduino/.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
This module requires an Arduino Uno, Nano, Jeenode, NodeMCU, Wemos D1 or similar device based on an Atmel 328p or ESP8266 running the ArduCounter sketch provided with this module&lt;br /&gt;
&lt;br /&gt;
In order to flash an arduino board with the corresponding ArduCounter firmware from within Fhem, avrdude needs to be installed.&lt;br /&gt;
&lt;br /&gt;
For old ferraris counters an Arduino Uno or Nano or ESP8266 board needs to be connected to a reflection light barrier which consists simply of an infra red photo transistor (connected to A7 on Arduinos and A0 on ESP8266) and an infra red led (connected to D2 on Arduinos and to D6 on ESP8266), both with a resistor in line.&lt;br /&gt;
&lt;br /&gt;
This module also requires Device::SerialPort or Win32::SerialPort for communication via serial lines&lt;br /&gt;
&lt;br /&gt;
== Define ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;define &amp;lt;name&amp;gt; ArduCounter &amp;lt;device&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
&amp;lt;pre&amp;gt;define &amp;lt;name&amp;gt; ArduCounter &amp;lt;ip:port&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;device&amp;gt; specifies the serial port to communicate with the Arduino.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ip:port&amp;gt; specifies the ip address and tcp port to communicate with an esp8266 where port is typically 80.&lt;br /&gt;
&lt;br /&gt;
The name of the serial-device depends on your distribution. You can also specify a baudrate for serial connections if the device name contains the @ character, e.g.: /dev/ttyUSB0@38400. The default baudrate of the ArduCounter firmware is 38400 since Version 1.4&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define AC ArduCounter /dev/ttyUSB2@38400&lt;br /&gt;
define AC ArduCounter 192.168.1.134:80&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configuration of ArduCounter digital counters ==&lt;br /&gt;
&lt;br /&gt;
Specify the pins where impulses should be counted e.g. as attr AC pinX falling pullup 30&lt;br /&gt;
&lt;br /&gt;
The X in pinX can be an Arduino / ESP pin number with or without the letter D e.g. pin4, pinD5, pin6, pinD7 ...&lt;br /&gt;
&lt;br /&gt;
After the pin you can use the keywords falling or rising to define if a logical one / 5V (rising) or a logical zero / 0V (falling) should be treated as pulse.&lt;br /&gt;
&lt;br /&gt;
The optional keyword pullup activates the pullup resistor for the given Pin.&lt;br /&gt;
&lt;br /&gt;
The last argument is also optional but recommended and specifies a minimal pulse length in milliseconds.&lt;br /&gt;
&lt;br /&gt;
An energy meter with S0 interface is typically connected to GND and an input pin like D4.&lt;br /&gt;
The S0 pulse then pulls the input to 0V.&lt;br /&gt;
Since the minimal pulse lenght of the s0 interface is specified to be 30ms, the typical configuration for an s0 interface is&lt;br /&gt;
attr AC pinX falling pullup 30&lt;br /&gt;
&lt;br /&gt;
Specifying a minimal pulse length is recommended since it filters bouncing of reed contacts or other noise.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define AC ArduCounter /dev/ttyUSB2&lt;br /&gt;
attr AC pulsesPerKWh 1000&lt;br /&gt;
attr AC interval 60 300&lt;br /&gt;
attr AC pinD4 falling pullup 5&lt;br /&gt;
attr AC pinD5 falling pullup 30&lt;br /&gt;
attr AC verboseReadingsD5&lt;br /&gt;
attr AC pinD6 rising&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
This defines three counters connected to the pins D4, D5 and D5.&lt;br /&gt;
D4 and D5 have their pullup resistors activated and the impulse draws the pins to zero.&lt;br /&gt;
For D4 and D5 the arduino measures the time in milliseconds between the falling edge and the rising edge. If this time is longer than the specified 5 or 30 milliseconds then the impulse is counted.&lt;br /&gt;
If the time is shorter then this impulse is regarded as noise and added to a separate reject counter.&lt;br /&gt;
&lt;br /&gt;
verboseReadings5 causes the module to create additional readings like the pin history which shows length and gaps between the last pulses.&lt;br /&gt;
&lt;br /&gt;
For pin D6 the arduino does not check pulse lengths and counts every time when the signal changes from 0 to 1.&lt;br /&gt;
&lt;br /&gt;
The ArduCounter sketch which must be loaded on the Arduino or ESP implements this using pin change interrupts, so all avilable input pins can be used, not only the ones that support normal interrupts.&lt;br /&gt;
The module has been tested with 14 inputs of an Arduino Uno counting in parallel and pulses as short as 3 milliseconds.&lt;br /&gt;
&lt;br /&gt;
== Configuration of ArduCounter analog counters ==&lt;br /&gt;
&lt;br /&gt;
This module and the corresponding sketch can be used to read out old analog ferraris energy counters. Therefore an ESP, Arduino Uno or Nano board needs to be connected to a reflection light barrier which consists simply of an infra red photo transistor (connected to A7 on Arduinos and A0 on ESP8266) and an infra red led (connected to D2 on Arduinos and to D6 on ESP8266), both with a resistor in line. The idea comes from Martin Kompf (https://www.kompf.de/tech/emeir.html) and has been adopted for ArduCounter to support old ferraris energy counters.&lt;br /&gt;
&lt;br /&gt;
To support this mode, the sketch has to be compiled with analogIR defined.&lt;br /&gt;
&lt;br /&gt;
The configuration is then similar to the one for digital counters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define ACF ArduCounter /dev/ttyUSB4&lt;br /&gt;
attr ACF analogThresholds 100 110&lt;br /&gt;
attr ACF flashCommand avrdude -p atmega328P -b57600 -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2&amp;gt;[LOGFILE]&lt;br /&gt;
attr ACF interval 60 300 2 2&lt;br /&gt;
attr ACF pinA7 rising 20&lt;br /&gt;
attr ACF pulsesPerKWh 75&lt;br /&gt;
attr ACF stateFormat {sprintf(&amp;quot;%.3f kW&amp;quot;, ReadingsVal($name,&amp;quot;powerA7&amp;quot;,0))}&lt;br /&gt;
&amp;lt;/pre&amp;gt;        &lt;br /&gt;
&lt;br /&gt;
To find out the right analog thresholds you can set devVerbose to 20 which will ask the firmware of your conting board to report every analog measurement. The ArduCounter module will count how often each value is reported and you can then query these analog level counts with get levels. After a few turns of the ferraris disc the result of get levels might look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
observed levels from analog input:&lt;br /&gt;
94: 21&lt;br /&gt;
95: 79&lt;br /&gt;
96: 6&lt;br /&gt;
97: 2&lt;br /&gt;
98: 3&lt;br /&gt;
99: 2&lt;br /&gt;
100: 2&lt;br /&gt;
101: 1&lt;br /&gt;
102: 3&lt;br /&gt;
105: 2&lt;br /&gt;
106: 1&lt;br /&gt;
108: 2&lt;br /&gt;
109: 1&lt;br /&gt;
110: 1&lt;br /&gt;
112: 1&lt;br /&gt;
113: 3&lt;br /&gt;
115: 4&lt;br /&gt;
116: 9&lt;br /&gt;
117: 14&lt;br /&gt;
118: 71&lt;br /&gt;
119: 103&lt;br /&gt;
120: 118&lt;br /&gt;
121: 155&lt;br /&gt;
122: 159&lt;br /&gt;
123: 143&lt;br /&gt;
124: 147&lt;br /&gt;
125: 158&lt;br /&gt;
126: 198&lt;br /&gt;
127: 249&lt;br /&gt;
128: 220&lt;br /&gt;
129: 230&lt;br /&gt;
130: 201&lt;br /&gt;
131: 140&lt;br /&gt;
132: 147&lt;br /&gt;
133: 153&lt;br /&gt;
134: 141&lt;br /&gt;
135: 119&lt;br /&gt;
136: 105&lt;br /&gt;
137: 109&lt;br /&gt;
138: 114&lt;br /&gt;
139: 83&lt;br /&gt;
140: 33&lt;br /&gt;
141: 14&lt;br /&gt;
142: 1      &lt;br /&gt;
&amp;lt;/pre&amp;gt;      &lt;br /&gt;
  &lt;br /&gt;
This shows the measured values together with the frequency how often the individual value has been measured. It is obvious that most measurements result in values between 120 and 135, very few values are betweem 96 and 115 and another peak is around the value 95.&lt;br /&gt;
It means that the when the red mark of the ferraris disc is under the sensor, the value is around 95 and while the blank disc is under the sensor, the value is typically between 120 and 135. So a good upper threshold would be 120 and a good lower threshold would be for example 96.&lt;br /&gt;
&lt;br /&gt;
== Get-Commands ==&lt;br /&gt;
;info &lt;br /&gt;
:send a command to the Arduino board to get current counts. &lt;br /&gt;
:This is not needed for normal operation but might be useful sometimes for debugging.&lt;br /&gt;
&lt;br /&gt;
;levels&lt;br /&gt;
:show the count for the measured levels if an analog pin is used to measure e.g. the red mark of a ferraris counter disc. &lt;br /&gt;
:This is useful for setting the thresholds for analog measurements.&lt;br /&gt;
&lt;br /&gt;
;history&lt;br /&gt;
:shows details regarding all the level changes that the counter device (Arduino or ESP) has detected &lt;br /&gt;
:and how they were used (counted or rejected)&lt;br /&gt;
:If get history is issued with a pin name (e.g. get history D5) then only the history entries concerning D5 will be shown.&lt;br /&gt;
:This information is sent from the device to Fhem when it reports the current count but only if devVerbose is equal or greater than 5.&lt;br /&gt;
:The maximum number of lines that the Arducounter module stores in a ring buffer is defined by the attribute maxHist and defaults to 1000.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Set-Commands ==&lt;br /&gt;
&lt;br /&gt;
;raw&lt;br /&gt;
:send the value to the board so you can directly talk to the sketch using its commands.&lt;br /&gt;
:This is not needed for normal operation but might be useful sometimes for debugging&lt;br /&gt;
&lt;br /&gt;
;flash&lt;br /&gt;
:flashes the ArduCounter firmware ArduCounter.hex from the fhem subdirectory FHEM/firmware onto the device. &lt;br /&gt;
:This command needs avrdude to be installed. The attribute flashCommand specidies how avrdude is called. &lt;br /&gt;
:If it is not modifed then the module sets it to avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2&amp;gt;[LOGFILE]&lt;br /&gt;
:This setting should work for a standard installation and the placeholders are automatically replaced when the command is used. &lt;br /&gt;
:So normally there is no need to modify this attribute.&lt;br /&gt;
:Depending on your specific Arduino board however, you might need to insert -b 57600 in the flash Command. &lt;br /&gt;
:(e.g. for an Arduino Nano) ESP boards so far have to be fashed from the Arduino IDE. In a future version flashing over the air sould be supported.&lt;br /&gt;
&lt;br /&gt;
;reset&lt;br /&gt;
:reopens the arduino device and sends a command to it which causes a reinitialize and reset of the counters. Then the module resends the attribute configuration / definition of the pins to the device.&lt;br /&gt;
&lt;br /&gt;
;saveConfig&lt;br /&gt;
:stores the current interval, analog threshold and pin configuration to be stored in the EEPROM of the counter device &lt;br /&gt;
:so it can be retrieved after a reset.&lt;br /&gt;
&lt;br /&gt;
;enable&lt;br /&gt;
:sets the attribute disable to 0&lt;br /&gt;
&lt;br /&gt;
;disable&lt;br /&gt;
:sets the attribute disable to 1&lt;br /&gt;
&lt;br /&gt;
;reconnect&lt;br /&gt;
:closes the tcp connection to an ESP based counter board that is conected via TCP/IP and reopen the connection&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Supported readings ==&lt;br /&gt;
The module creates at least the following readings and events for each defined pin:&lt;br /&gt;
&lt;br /&gt;
;pin.* e.g. pinD4&lt;br /&gt;
:the current internal count at this pin (internal to the Arduino / ESP device, starts at 0 when the device restarts).&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNameCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;long.* e.g. longD5&lt;br /&gt;
:long count which keeps on counting up after fhem restarts whereas the pin.* count is only a temporary internal count that starts at 0 when the arduino board starts.&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNameLongCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;interpolatedLong.*&lt;br /&gt;
:like long.* but when the Arduino restarts the potentially missed pulses are interpolated based on the pulse rate before the restart and after the restart.&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNameInterpolatedCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;calcCounter.*&lt;br /&gt;
:similar to long count which keeps on counting up after fhem restarts but this counter will take the pulses per kWh setting into the :calculation und thus not count pulses but real kWh (or some other unit that is applicable)&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNameCalcCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;reject.*&lt;br /&gt;
:counts rejected pulses that are shorter than the specified minimal pulse length.&lt;br /&gt;
&lt;br /&gt;
;power.*&lt;br /&gt;
:the current calculated power at this pin.&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNamePower[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;pinHistory.*&lt;br /&gt;
:shows detailed information of the last pulses. This is only available when a minimal pulse length is specified for this pin. Also the total number of impulses recorded here is limited to 20 for all pins together. The output looks like -36/7:0C, -29/7:1G, -22/8:0C, -14/7:1G, -7/7:0C, 0/7:1G&lt;br /&gt;
:The first number is the relative time in milliseconds when the input level changed, followed by the length in milliseconds, the level and the internal action. -36/7:0C for example means that 36 milliseconds before the reporting started, the input changed to 0V, stayed there for 7 milliseconds and this was counted.&lt;br /&gt;
&lt;br /&gt;
;countDiff.*&lt;br /&gt;
:delta of the current count to the last reported one. This is used together with timeDiff.* to calculate the power consumption.&lt;br /&gt;
&lt;br /&gt;
;timeDiff.*&lt;br /&gt;
:time difference between the first pulse in the current observation interval and the last one. Used togehter with countDiff to calculate the power consumption.&lt;br /&gt;
&lt;br /&gt;
;seq.*&lt;br /&gt;
:internal sequence number of the last report from the board to Fhem.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Attributes ==&lt;br /&gt;
&lt;br /&gt;
;do_not_notify&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
;pin.* &lt;br /&gt;
:Define a pin of the Arduino board as input. This attribute expects either &amp;lt;code&amp;gt;rising&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;falling&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;change&amp;lt;/code&amp;gt;, followed by an optional &amp;lt;code&amp;gt;pullup&amp;lt;/code&amp;gt; and an optional number as value.&lt;br /&gt;
:If a number is specified, the arduino will track rising and falling edges of each impulse and measure the length of a pulse in milliseconds. &lt;br /&gt;
:The number specified here is the minimal length of a pulse and a pause before a pulse. If one is too small, the pulse is not counted but added to a separate reject counter.&lt;br /&gt;
&lt;br /&gt;
;interval normal max min mincout &lt;br /&gt;
:Defines the parameters that affect the way counting and reporting works.&lt;br /&gt;
:This Attribute expects at least two and a maximum of four numbers as value. &lt;br /&gt;
: The first is the normal interval, the second the maximal interval, the third is a minimal interval and the fourth is a minimal pulse count.&lt;br /&gt;
&lt;br /&gt;
:In the usual operation mode (when the normal interval is smaller than the maximum interval), the Arduino board just counts and remembers the time between the first impulse and the last impulse for each pin.&lt;br /&gt;
:After the normal interval is elapsed the Arduino board reports the count and time for those pins where impulses were encountered.&lt;br /&gt;
:This means that even though the normal interval might be 10 seconds, the reported time difference can be something different because it observed impulses as starting and ending point.&lt;br /&gt;
:The Power (e.g. for energy meters) is the calculated based of the counted impulses and the time between the first and the last impulse. &lt;br /&gt;
:For the next interval, the starting time will be the time of the last impulse in the previous reporting period and the time difference will be taken up to the last impulse before the reporting interval has elapsed.&lt;br /&gt;
&lt;br /&gt;
:The second, third and fourth numbers (maximum, minimal interval and minimal count) exist for the special case when the pulse frequency is very low and the reporting time is comparatively short.&lt;br /&gt;
:For example if the normal interval (first number) is 60 seconds and the device counts only one impulse in 90 seconds, the the calculated power reading will jump up and down and will give ugly numbers.&lt;br /&gt;
:By adjusting the other numbers of this attribute this can be avoided.&lt;br /&gt;
:In case in the normal interval the observed impulses are encountered in a time difference that is smaller than the third number (minimal interval) or if the number of impulses counted is smaller than the fourth number (minimal count) then the reporting is delayed until the maximum interval has elapsed or the above conditions have changed after another normal interval.&lt;br /&gt;
:This way the counter will report a higher number of pulses counted and a larger time difference back to fhem.&lt;br /&gt;
&lt;br /&gt;
:If this is seems too complicated and you prefer a simple and constant reporting interval, then you can set the normal interval and the mximum interval to the same number. This changes the operation mode of the counter to just count during this normal and maximum interval and report the count. In this case the reported time difference is always the reporting interval and not the measured time between the real impulses.&lt;br /&gt;
&lt;br /&gt;
;factor &lt;br /&gt;
:Define a multiplicator for calculating the power from the impulse count and the time between the first and the last impulse.&lt;br /&gt;
:This attribute is outdated and unintuitive so you should avoid it.&lt;br /&gt;
:Instead you should specify the attribute pulsesPerKWh or readingPulsesPerKWh[0-9]+ (where [0-9]+ stands for the pin number).&lt;br /&gt;
&lt;br /&gt;
;readingFactor[0-9]+&lt;br /&gt;
:Override the factor attribute for this individual pin.&lt;br /&gt;
:Just like the attribute factor, this is a rather cumbersome way to specify the pulses per kWh.&lt;br /&gt;
:Instaed it is advised to use the attribute pulsesPerKWh or readingPulsesPerKWh[0-9]+ (where [0-9]+ stands for the pin number).&lt;br /&gt;
&lt;br /&gt;
;pulsesPerKWh&lt;br /&gt;
:specify the number of pulses that the meter is giving out per unit that sould be displayed (e.g. per kWh energy consumed). For many S0 counters this is 1000, for old ferraris counters this is 75 (rounds per kWh).&lt;br /&gt;
:Example: attr myCounter pulsesPerKWh 75&lt;br /&gt;
&lt;br /&gt;
;readingPulsesPerKWh[0-9]+&lt;br /&gt;
:is the same as pulsesPerKWh but specified per pin individually in case you have multiple counters with different settings at the same time&lt;br /&gt;
:Example:&lt;br /&gt;
:attr myCounter readingPulsesPerKWhA7 75&lt;br /&gt;
:attr myCounter readingPulsesPerKWhD4 1000&lt;br /&gt;
&lt;br /&gt;
;readingNameCount[0-9]+ &lt;br /&gt;
:Change the name of the counter reading pinX to something more meaningful.&lt;br /&gt;
&lt;br /&gt;
;readingNameLongCount[0-9]+ &lt;br /&gt;
:Change the name of the counter reading longX to something more meaningful.&lt;br /&gt;
&lt;br /&gt;
;readingNameInterpolatedCount[0-9]+ &lt;br /&gt;
:Change the name of the counter reading InterpolatedLongX to something more meaningful.&lt;br /&gt;
&lt;br /&gt;
;readingNameCalcCount[AD]?[0-9]+&lt;br /&gt;
:Change the name of the real unit counter reading CalcCounterX to something more meaningful.&lt;br /&gt;
:Example: attr myCounter readingNameCalcCountD4 CounterHaus_kWh&lt;br /&gt;
&lt;br /&gt;
;readingNamePower[0-9]+ &lt;br /&gt;
:Change the name of the power reading powerX to something more meaningful.&lt;br /&gt;
&lt;br /&gt;
;readingStartTime[0-9]+ &lt;br /&gt;
:Allow the reading time stamp to be set to the beginning of measuring intervals&lt;br /&gt;
&lt;br /&gt;
;verboseReadings[0-9]+ &lt;br /&gt;
:create additional readings: timeDiff, countDiff and lastMsg for each pin&lt;br /&gt;
&lt;br /&gt;
;devVerbose&lt;br /&gt;
:set the verbose level in the counting board. This defaults to 0.&lt;br /&gt;
:If the value is &amp;gt;0, then the firmware will echo all commands sent to it by the Fhem module.&lt;br /&gt;
:If the value is &amp;gt;=5, then the firmware will report the pin history (assuming that the firmware has been compiled with this feature enabled)&lt;br /&gt;
:If the value is &amp;gt;=10, then the firmware will report every level change of a pin&lt;br /&gt;
:If the value is &amp;gt;=20, then the firmware will report every analog measurement (assuming that the firmware has been compiled with analog measurements for old ferraris counters or similar).&lt;br /&gt;
&lt;br /&gt;
;maxHist&lt;br /&gt;
:specifies how many pin history lines hould be buffered for &amp;quot;get history&amp;quot;.&lt;br /&gt;
:This attribute defaults to 1000.&lt;br /&gt;
&lt;br /&gt;
;analogThresholds&lt;br /&gt;
:this Attribute is necessary when you use an arduino nano with connected reflection light barrier (photo transistor and led) to detect the red mark of an old ferraris energy counter. In this case the firmware uses an upper and lower threshold which can be set here.&lt;br /&gt;
:Example: attr myCounter analogThresholds 90 110&lt;br /&gt;
:In order to find out the right threshold values you can set devVerbose to 20, wait for several turns of the ferraris disc and then use get levels to see the typical measurements for the red mark and the blank disc.&lt;br /&gt;
&lt;br /&gt;
;flashCommand&lt;br /&gt;
:sets the command to call avrdude and flash the onnected arduino with an updated hex file (by default it looks for ArduCounter.hex in the FHEM/firmware subdirectory.&lt;br /&gt;
:This attribute contains avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2&amp;gt;[LOGFILE] by default.&lt;br /&gt;
:For an Arduino Nano based counter you should add -b 57600 e.g. between the -P and -D options.&lt;br /&gt;
:Example: attr myCounter flashCommand avrdude -p atmega328P -c arduino -b 57600 -P [PORT] -D -U flash:w:[HEXFILE] 2&amp;gt;[LOGFILE]&lt;br /&gt;
&lt;br /&gt;
;keepAliveDelay&lt;br /&gt;
:defines an interval in which the module sends keepalive messages to a counter device that is conected via tcp.&lt;br /&gt;
:This attribute is ignored if the device is connected via serial port.&lt;br /&gt;
:If the device doesn&#039;t reply within a defined timeout then the module closes and tries to reopen the connection.&lt;br /&gt;
:The module tells the device when to expect the next keepalive message and the device will also close the tcp connection if it doesn&#039;t see a :keepalive message within the delay multiplied by 3&lt;br /&gt;
:The delay defaults to 10 seconds.&lt;br /&gt;
:Example: attr myCounter keepAliveDelay 30&lt;br /&gt;
&lt;br /&gt;
;keepAliveTimeout&lt;br /&gt;
:defines the timeout when wainting for a keealive reply (see keepAliveDelay) The timeout defaults to 2 seconds.&lt;br /&gt;
:Example: attr myCounter keepAliveTimeout 3&lt;br /&gt;
&lt;br /&gt;
;keepAliveRetries&lt;br /&gt;
:defines how often sending a keepalive is retried before the connection is closed and reopened.&lt;br /&gt;
:It defaults to 2.&lt;br /&gt;
:Example: attr myCounter keepAliveRetries 3&lt;br /&gt;
&lt;br /&gt;
;nextOpenDelay&lt;br /&gt;
:defines the time that the module waits before retrying to open a disconnected tcp connection.&lt;br /&gt;
:This defaults to 60 seconds.&lt;br /&gt;
:Example: attr myCounter nextOpenDelay 20&lt;br /&gt;
&lt;br /&gt;
;openTimeout&lt;br /&gt;
:defines the timeout after which tcp open gives up trying to establish a connection to the counter device. This timeout defaults to 3 seconds.&lt;br /&gt;
:Example: attr myCounter openTimeout 5&lt;br /&gt;
&lt;br /&gt;
;silentReconnect&lt;br /&gt;
:if set to 1, then it will set the loglevel for &amp;quot;disconnected&amp;quot; and &amp;quot;reappeared&amp;quot; messages to 4 instead of 3&lt;br /&gt;
:Example: attr myCounter silentReconnect 1&lt;br /&gt;
&lt;br /&gt;
;disable&lt;br /&gt;
:if set to 1 then the module closes the connection to a counter device.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Other Components]]&lt;br /&gt;
[[Kategorie:Energieverbrauchsmessung]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=ArduCounter&amp;diff=32256</id>
		<title>ArduCounter</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=ArduCounter&amp;diff=32256"/>
		<updated>2020-01-01T22:53:40Z</updated>

		<summary type="html">&lt;p&gt;Maista: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Modul&lt;br /&gt;
|ModPurpose=Count pulses, calculate time between pulses and convert this to readings for e.g. power consumption of Energy meters&lt;br /&gt;
|ModType=contrib&lt;br /&gt;
|ModCmdRef=ArduCounter&lt;br /&gt;
|ModForumArea=Sonstiges&lt;br /&gt;
|ModFTopic=19285&lt;br /&gt;
|ModTechName=98_ArduCounter.pm&lt;br /&gt;
|ModOwner=StefanStrobel ({{Link2FU|3960|Forum}} / [[Benutzer:StefanStrobel|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
This module implements an Interface to an Arduino or ESP8266 based counter for pulses on any input pin of an Arduino Uno, Nano, Jeenode, NodeMCU, Wemos D1 or similar device. The device connects to FHEM either through USB / serial or via tcp if an ESP board is used.&lt;br /&gt;
&lt;br /&gt;
The typical use case is an S0-Interface on an energy meter or water meter, but also reflection light barriers to monitor old ferraris counters are supported&lt;br /&gt;
&lt;br /&gt;
Counters are configured with attributes that define which Arduino pins should count pulses and in which intervals the Arduino board should report the current counts.&lt;br /&gt;
&lt;br /&gt;
The Arduino sketch that works with this module uses pin change interrupts so it can efficiently count pulses on all available input pins.&lt;br /&gt;
The module creates readings for pulse counts, consumption and optionally also a pin history with pulse lengths and gaps of the last pulses.&lt;br /&gt;
&lt;br /&gt;
== Availability == &lt;br /&gt;
The module has been checked in to the FHEM svn. &lt;br /&gt;
The corresponding arduino sketch can also be found under contrib in the subdirectory arduino/.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
This module requires an Arduino Uno, Nano, Jeenode, NodeMCU, Wemos D1 or similar device based on an Atmel 328p or ESP8266 running the ArduCounter sketch provided with this module&lt;br /&gt;
&lt;br /&gt;
In order to flash an arduino board with the corresponding ArduCounter firmware from within Fhem, avrdude needs to be installed.&lt;br /&gt;
&lt;br /&gt;
For old ferraris counters an Arduino Uno or Nano or ESP8266 board needs to be connected to a reflection light barrier which consists simply of an infra red photo transistor (connected to A7 on Arduinos and A0 on ESP8266) and an infra red led (connected to D2 on Arduinos and to D6 on ESP8266), both with a resistor in line.&lt;br /&gt;
&lt;br /&gt;
This module also requires Device::SerialPort or Win32::SerialPort for communication via serial lines&lt;br /&gt;
&lt;br /&gt;
== Define ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;define &amp;lt;name&amp;gt; ArduCounter &amp;lt;device&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
&amp;lt;pre&amp;gt;define &amp;lt;name&amp;gt; ArduCounter &amp;lt;ip:port&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;device&amp;gt; specifies the serial port to communicate with the Arduino.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ip:port&amp;gt; specifies the ip address and tcp port to communicate with an esp8266 where port is typically 80.&lt;br /&gt;
&lt;br /&gt;
The name of the serial-device depends on your distribution. You can also specify a baudrate for serial connections if the device name contains the @ character, e.g.: /dev/ttyUSB0@38400. The default baudrate of the ArduCounter firmware is 38400 since Version 1.4&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define AC ArduCounter /dev/ttyUSB2@38400&lt;br /&gt;
define AC ArduCounter 192.168.1.134:80&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configuration of ArduCounter digital counters ==&lt;br /&gt;
&lt;br /&gt;
Specify the pins where impulses should be counted e.g. as attr AC pinX falling pullup 30&lt;br /&gt;
&lt;br /&gt;
The X in pinX can be an Arduino / ESP pin number with or without the letter D e.g. pin4, pinD5, pin6, pinD7 ...&lt;br /&gt;
&lt;br /&gt;
After the pin you can use the keywords falling or rising to define if a logical one / 5V (rising) or a logical zero / 0V (falling) should be treated as pulse.&lt;br /&gt;
&lt;br /&gt;
The optional keyword pullup activates the pullup resistor for the given Pin.&lt;br /&gt;
&lt;br /&gt;
The last argument is also optional but recommended and specifies a minimal pulse length in milliseconds.&lt;br /&gt;
&lt;br /&gt;
An energy meter with S0 interface is typically connected to GND and an input pin like D4.&lt;br /&gt;
The S0 pulse then pulls the input to 0V.&lt;br /&gt;
Since the minimal pulse lenght of the s0 interface is specified to be 30ms, the typical configuration for an s0 interface is&lt;br /&gt;
attr AC pinX falling pullup 30&lt;br /&gt;
&lt;br /&gt;
Specifying a minimal pulse length is recommended since it filters bouncing of reed contacts or other noise.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define AC ArduCounter /dev/ttyUSB2&lt;br /&gt;
attr AC pulsesPerKWh 1000&lt;br /&gt;
attr AC interval 60 300&lt;br /&gt;
attr AC pinD4 falling pullup 5&lt;br /&gt;
attr AC pinD5 falling pullup 30&lt;br /&gt;
attr AC verboseReadingsD5&lt;br /&gt;
attr AC pinD6 rising&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
This defines three counters connected to the pins D4, D5 and D5.&lt;br /&gt;
D4 and D5 have their pullup resistors activated and the impulse draws the pins to zero.&lt;br /&gt;
For D4 and D5 the arduino measures the time in milliseconds between the falling edge and the rising edge. If this time is longer than the specified 5 or 30 milliseconds then the impulse is counted.&lt;br /&gt;
If the time is shorter then this impulse is regarded as noise and added to a separate reject counter.&lt;br /&gt;
&lt;br /&gt;
verboseReadings5 causes the module to create additional readings like the pin history which shows length and gaps between the last pulses.&lt;br /&gt;
&lt;br /&gt;
For pin D6 the arduino does not check pulse lengths and counts every time when the signal changes from 0 to 1.&lt;br /&gt;
&lt;br /&gt;
The ArduCounter sketch which must be loaded on the Arduino or ESP implements this using pin change interrupts, so all avilable input pins can be used, not only the ones that support normal interrupts.&lt;br /&gt;
The module has been tested with 14 inputs of an Arduino Uno counting in parallel and pulses as short as 3 milliseconds.&lt;br /&gt;
&lt;br /&gt;
== Configuration of ArduCounter analog counters ==&lt;br /&gt;
&lt;br /&gt;
This module and the corresponding sketch can be used to read out old analog ferraris energy counters. Therefore an ESP, Arduino Uno or Nano board needs to be connected to a reflection light barrier which consists simply of an infra red photo transistor (connected to A7 on Arduinos and A0 on ESP8266) and an infra red led (connected to D2 on Arduinos and to D6 on ESP8266), both with a resistor in line. The idea comes from Martin Kompf (https://www.kompf.de/tech/emeir.html) and has been adopted for ArduCounter to support old ferraris energy counters.&lt;br /&gt;
&lt;br /&gt;
To support this mode, the sketch has to be compiled with analogIR defined.&lt;br /&gt;
&lt;br /&gt;
The configuration is then similar to the one for digital counters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define ACF ArduCounter /dev/ttyUSB4&lt;br /&gt;
attr ACF analogThresholds 100 110&lt;br /&gt;
attr ACF flashCommand avrdude -p atmega328P -b57600 -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2&amp;gt;[LOGFILE]&lt;br /&gt;
attr ACF interval 60 300 2 2&lt;br /&gt;
attr ACF pinA7 rising 20&lt;br /&gt;
attr ACF pulsesPerKWh 75&lt;br /&gt;
attr ACF stateFormat {sprintf(&amp;quot;%.3f kW&amp;quot;, ReadingsVal($name,&amp;quot;powerA7&amp;quot;,0))}&lt;br /&gt;
&amp;lt;/pre&amp;gt;        &lt;br /&gt;
&lt;br /&gt;
To find out the right analog thresholds you can set devVerbose to 20 which will ask the firmware of your conting board to report every analog measurement. The ArduCounter module will count how often each value is reported and you can then query these analog level counts with get levels. After a few turns of the ferraris disc the result of get levels might look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
observed levels from analog input:&lt;br /&gt;
94: 21&lt;br /&gt;
95: 79&lt;br /&gt;
96: 6&lt;br /&gt;
97: 2&lt;br /&gt;
98: 3&lt;br /&gt;
99: 2&lt;br /&gt;
100: 2&lt;br /&gt;
101: 1&lt;br /&gt;
102: 3&lt;br /&gt;
105: 2&lt;br /&gt;
106: 1&lt;br /&gt;
108: 2&lt;br /&gt;
109: 1&lt;br /&gt;
110: 1&lt;br /&gt;
112: 1&lt;br /&gt;
113: 3&lt;br /&gt;
115: 4&lt;br /&gt;
116: 9&lt;br /&gt;
117: 14&lt;br /&gt;
118: 71&lt;br /&gt;
119: 103&lt;br /&gt;
120: 118&lt;br /&gt;
121: 155&lt;br /&gt;
122: 159&lt;br /&gt;
123: 143&lt;br /&gt;
124: 147&lt;br /&gt;
125: 158&lt;br /&gt;
126: 198&lt;br /&gt;
127: 249&lt;br /&gt;
128: 220&lt;br /&gt;
129: 230&lt;br /&gt;
130: 201&lt;br /&gt;
131: 140&lt;br /&gt;
132: 147&lt;br /&gt;
133: 153&lt;br /&gt;
134: 141&lt;br /&gt;
135: 119&lt;br /&gt;
136: 105&lt;br /&gt;
137: 109&lt;br /&gt;
138: 114&lt;br /&gt;
139: 83&lt;br /&gt;
140: 33&lt;br /&gt;
141: 14&lt;br /&gt;
142: 1      &lt;br /&gt;
&amp;lt;/pre&amp;gt;      &lt;br /&gt;
  &lt;br /&gt;
This shows the measured values together with the frequency how often the individual value has been measured. It is obvious that most measurements result in values between 120 and 135, very few values are betweem 96 and 115 and another peak is around the value 95.&lt;br /&gt;
It means that the when the red mark of the ferraris disc is under the sensor, the value is around 95 and while the blank disc is under the sensor, the value is typically between 120 and 135. So a good upper threshold would be 120 and a good lower threshold would be for example 96.&lt;br /&gt;
&lt;br /&gt;
== Get-Commands ==&lt;br /&gt;
;info &lt;br /&gt;
:send a command to the Arduino board to get current counts. &lt;br /&gt;
:This is not needed for normal operation but might be useful sometimes for debugging.&lt;br /&gt;
&lt;br /&gt;
;levels&lt;br /&gt;
:show the count for the measured levels if an analog pin is used to measure e.g. the red mark of a ferraris counter disc. &lt;br /&gt;
:This is useful for setting the thresholds for analog measurements.&lt;br /&gt;
&lt;br /&gt;
;history&lt;br /&gt;
:shows details regarding all the level changes that the counter device (Arduino or ESP) has detected &lt;br /&gt;
:and how they were used (counted or rejected)&lt;br /&gt;
:If get history is issued with a pin name (e.g. get history D5) then only the history entries concerning D5 will be shown.&lt;br /&gt;
:This information is sent from the device to Fhem when it reports the current count but only if devVerbose is equal or greater than 5.&lt;br /&gt;
:The maximum number of lines that the Arducounter module stores in a ring buffer is defined by the attribute maxHist and defaults to 1000.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Set-Commands ==&lt;br /&gt;
&lt;br /&gt;
;raw&lt;br /&gt;
:send the value to the board so you can directly talk to the sketch using its commands.&lt;br /&gt;
:This is not needed for normal operation but might be useful sometimes for debugging&lt;br /&gt;
&lt;br /&gt;
;flash&lt;br /&gt;
:flashes the ArduCounter firmware ArduCounter.hex from the fhem subdirectory FHEM/firmware onto the device. &lt;br /&gt;
:This command needs avrdude to be installed. The attribute flashCommand specidies how avrdude is called. &lt;br /&gt;
:If it is not modifed then the module sets it to avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2&amp;gt;[LOGFILE]&lt;br /&gt;
:This setting should work for a standard installation and the placeholders are automatically replaced when the command is used. &lt;br /&gt;
:So normally there is no need to modify this attribute.&lt;br /&gt;
:Depending on your specific Arduino board however, you might need to insert -b 57600 in the flash Command. &lt;br /&gt;
:(e.g. for an Arduino Nano) ESP boards so far have to be fashed from the Arduino IDE. In a future version flashing over the air sould be supported.&lt;br /&gt;
&lt;br /&gt;
;reset&lt;br /&gt;
:reopens the arduino device and sends a command to it which causes a reinitialize and reset of the counters. Then the module resends the attribute configuration / definition of the pins to the device.&lt;br /&gt;
&lt;br /&gt;
;saveConfig&lt;br /&gt;
:stores the current interval, analog threshold and pin configuration to be stored in the EEPROM of the counter device &lt;br /&gt;
:so it can be retrieved after a reset.&lt;br /&gt;
&lt;br /&gt;
;enable&lt;br /&gt;
:sets the attribute disable to 0&lt;br /&gt;
&lt;br /&gt;
;disable&lt;br /&gt;
:sets the attribute disable to 1&lt;br /&gt;
&lt;br /&gt;
;reconnect&lt;br /&gt;
:closes the tcp connection to an ESP based counter board that is conected via TCP/IP and reopen the connection&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Supported readings ==&lt;br /&gt;
The module creates at least the following readings and events for each defined pin:&lt;br /&gt;
&lt;br /&gt;
;pin.* e.g. pinD4&lt;br /&gt;
:the current internal count at this pin (internal to the Arduino / ESP device, starts at 0 when the device restarts).&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNameCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;long.* e.g. longD5&lt;br /&gt;
:long count which keeps on counting up after fhem restarts whereas the pin.* count is only a temporary internal count that starts at 0 when the arduino board starts.&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNameLongCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;interpolatedLong.*&lt;br /&gt;
:like long.* but when the Arduino restarts the potentially missed pulses are interpolated based on the pulse rate before the restart and after the restart.&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNameInterpolatedCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;calcCounter.*&lt;br /&gt;
:similar to long count which keeps on counting up after fhem restarts but this counter will take the pulses per kWh setting into the :calculation und thus not count pulses but real kWh (or some other unit that is applicable)&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNameCalcCount[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;reject.*&lt;br /&gt;
:counts rejected pulses that are shorter than the specified minimal pulse length.&lt;br /&gt;
&lt;br /&gt;
;power.*&lt;br /&gt;
:the current calculated power at this pin.&lt;br /&gt;
:The name of this reading can be changed with the attribute readingNamePower[AD]?[0-9]+ where [AD]?[0-9]+ stands for the pin description e.g. D4&lt;br /&gt;
&lt;br /&gt;
;pinHistory.*&lt;br /&gt;
:shows detailed information of the last pulses. This is only available when a minimal pulse length is specified for this pin. Also the total number of impulses recorded here is limited to 20 for all pins together. The output looks like -36/7:0C, -29/7:1G, -22/8:0C, -14/7:1G, -7/7:0C, 0/7:1G&lt;br /&gt;
:The first number is the relative time in milliseconds when the input level changed, followed by the length in milliseconds, the level and the internal action. -36/7:0C for example means that 36 milliseconds before the reporting started, the input changed to 0V, stayed there for 7 milliseconds and this was counted.&lt;br /&gt;
&lt;br /&gt;
;countDiff.*&lt;br /&gt;
:delta of the current count to the last reported one. This is used together with timeDiff.* to calculate the power consumption.&lt;br /&gt;
&lt;br /&gt;
;timeDiff.*&lt;br /&gt;
:time difference between the first pulse in the current observation interval and the last one. Used togehter with countDiff to calculate the power consumption.&lt;br /&gt;
&lt;br /&gt;
;seq.*&lt;br /&gt;
:internal sequence number of the last report from the board to Fhem.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Attributes ==&lt;br /&gt;
&lt;br /&gt;
;do_not_notify&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
;pin.* &lt;br /&gt;
:Define a pin of the Arduino board as input. This attribute expects either &amp;lt;code&amp;gt;rising&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;falling&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;change&amp;lt;/code&amp;gt;, followed by an optional &amp;lt;code&amp;gt;pullup&amp;lt;/code&amp;gt; and an optional number as value.&lt;br /&gt;
:If a number is specified, the arduino will track rising and falling edges of each impulse and measure the length of a pulse in milliseconds. &lt;br /&gt;
:The number specified here is the minimal length of a pulse and a pause before a pulse. If one is too small, the pulse is not counted but added to a separate reject counter.&lt;br /&gt;
&lt;br /&gt;
;interval normal max min mincout &lt;br /&gt;
:Defines the parameters that affect the way counting and reporting works.&lt;br /&gt;
:This Attribute expects at least two and a maximum of four numbers as value. &lt;br /&gt;
: The first is the normal interval, the second the maximal interval, the third is a minimal interval and the fourth is a minimal pulse count.&lt;br /&gt;
&lt;br /&gt;
:In the usual operation mode (when the normal interval is smaller than the maximum interval), the Arduino board just counts and remembers the time between the first impulse and the last impulse for each pin.&lt;br /&gt;
:After the normal interval is elapsed the Arduino board reports the count and time for those pins where impulses were encountered.&lt;br /&gt;
:This means that even though the normal interval might be 10 seconds, the reported time difference can be something different because it observed impulses as starting and ending point.&lt;br /&gt;
:The Power (e.g. for energy meters) is the calculated based of the counted impulses and the time between the first and the last impulse. &lt;br /&gt;
:For the next interval, the starting time will be the time of the last impulse in the previous reporting period and the time difference will be taken up to the last impulse before the reporting interval has elapsed.&lt;br /&gt;
&lt;br /&gt;
:The second, third and fourth numbers (maximum, minimal interval and minimal count) exist for the special case when the pulse frequency is very low and the reporting time is comparatively short.&lt;br /&gt;
:For example if the normal interval (first number) is 60 seconds and the device counts only one impulse in 90 seconds, the the calculated power reading will jump up and down and will give ugly numbers.&lt;br /&gt;
:By adjusting the other numbers of this attribute this can be avoided.&lt;br /&gt;
:In case in the normal interval the observed impulses are encountered in a time difference that is smaller than the third number (minimal interval) or if the number of impulses counted is smaller than the fourth number (minimal count) then the reporting is delayed until the maximum interval has elapsed or the above conditions have changed after another normal interval.&lt;br /&gt;
:This way the counter will report a higher number of pulses counted and a larger time difference back to fhem.&lt;br /&gt;
&lt;br /&gt;
:If this is seems too complicated and you prefer a simple and constant reporting interval, then you can set the normal interval and the mximum interval to the same number. This changes the operation mode of the counter to just count during this normal and maximum interval and report the count. In this case the reported time difference is always the reporting interval and not the measured time between the real impulses.&lt;br /&gt;
&lt;br /&gt;
;factor &lt;br /&gt;
:Define a multiplicator for calculating the power from the impulse count and the time between the first and the last impulse.&lt;br /&gt;
:This attribute is outdated and unintuitive so you should avoid it.&lt;br /&gt;
:Instead you should specify the attribute pulsesPerKWh or readingPulsesPerKWh[0-9]+ (where [0-9]+ stands for the pin number).&lt;br /&gt;
&lt;br /&gt;
;readingFactor[0-9]+&lt;br /&gt;
:Override the factor attribute for this individual pin.&lt;br /&gt;
:Just like the attribute factor, this is a rather cumbersome way to specify the pulses per kWh.&lt;br /&gt;
:Instaed it is advised to use the attribute pulsesPerKWh or readingPulsesPerKWh[0-9]+ (where [0-9]+ stands for the pin number).&lt;br /&gt;
&lt;br /&gt;
;pulsesPerKWh&lt;br /&gt;
:specify the number of pulses that the meter is giving out per unit that sould be displayed (e.g. per kWh energy consumed). For many S0 counters this is 1000, for old ferraris counters this is 75 (rounds per kWh).&lt;br /&gt;
:Example: attr myCounter pulsesPerKWh 75&lt;br /&gt;
&lt;br /&gt;
;readingPulsesPerKWh[0-9]+&lt;br /&gt;
:is the same as pulsesPerKWh but specified per pin individually in case you have multiple counters with different settings at the same time&lt;br /&gt;
:Example:&lt;br /&gt;
:attr myCounter readingPulsesPerKWhA7 75&lt;br /&gt;
:attr myCounter readingPulsesPerKWhD4 1000&lt;br /&gt;
&lt;br /&gt;
;readingNameCount[0-9]+ &lt;br /&gt;
:Change the name of the counter reading pinX to something more meaningful.&lt;br /&gt;
&lt;br /&gt;
;readingNameLongCount[0-9]+ &lt;br /&gt;
:Change the name of the counter reading longX to something more meaningful.&lt;br /&gt;
&lt;br /&gt;
;readingNameInterpolatedCount[0-9]+ &lt;br /&gt;
:Change the name of the counter reading InterpolatedLongX to something more meaningful.&lt;br /&gt;
&lt;br /&gt;
;readingNameCalcCount[AD]?[0-9]+&lt;br /&gt;
:Change the name of the real unit counter reading CalcCounterX to something more meaningful.&lt;br /&gt;
:Example: attr myCounter readingNameCalcCountD4 CounterHaus_kWh&lt;br /&gt;
&lt;br /&gt;
;readingNamePower[0-9]+ &lt;br /&gt;
:Change the name of the power reading powerX to something more meaningful.&lt;br /&gt;
&lt;br /&gt;
;readingStartTime[0-9]+ &lt;br /&gt;
:Allow the reading time stamp to be set to the beginning of measuring intervals&lt;br /&gt;
&lt;br /&gt;
;verboseReadings[0-9]+ &lt;br /&gt;
:create additional readings: timeDiff, countDiff and lastMsg for each pin&lt;br /&gt;
&lt;br /&gt;
;devVerbose&lt;br /&gt;
:set the verbose level in the counting board. This defaults to 0.&lt;br /&gt;
:If the value is &amp;gt;0, then the firmware will echo all commands sent to it by the Fhem module.&lt;br /&gt;
:If the value is &amp;gt;=5, then the firmware will report the pin history (assuming that the firmware has been compiled with this feature enabled)&lt;br /&gt;
:If the value is &amp;gt;=10, then the firmware will report every level change of a pin&lt;br /&gt;
:If the value is &amp;gt;=20, then the firmware will report every analog measurement (assuming that the firmware has been compiled with analog measurements for old ferraris counters or similar).&lt;br /&gt;
&lt;br /&gt;
;maxHist&lt;br /&gt;
:specifies how many pin history lines hould be buffered for &amp;quot;get history&amp;quot;.&lt;br /&gt;
:This attribute defaults to 1000.&lt;br /&gt;
&lt;br /&gt;
;analogThresholds&lt;br /&gt;
:this Attribute is necessary when you use an arduino nano with connected reflection light barrier (photo transistor and led) to detect the red mark of an old ferraris energy counter. In this case the firmware uses an upper and lower threshold which can be set here.&lt;br /&gt;
:Example: attr myCounter analogThresholds 90 110&lt;br /&gt;
:In order to find out the right threshold values you can set devVerbose to 20, wait for several turns of the ferraris disc and then use get levels to see the typical measurements for the red mark and the blank disc.&lt;br /&gt;
&lt;br /&gt;
;flashCommand&lt;br /&gt;
:sets the command to call avrdude and flash the onnected arduino with an updated hex file (by default it looks for ArduCounter.hex in the FHEM/firmware subdirectory.&lt;br /&gt;
:This attribute contains avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2&amp;gt;[LOGFILE] by default.&lt;br /&gt;
:For an Arduino Nano based counter you should add -b 57600 e.g. between the -P and -D options.&lt;br /&gt;
:Example: attr myCounter flashCommand avrdude -p atmega328P -c arduino -b 57600 -P [PORT] -D -U flash:w:[HEXFILE] 2&amp;gt;[LOGFILE]&lt;br /&gt;
&lt;br /&gt;
;keepAliveDelay&lt;br /&gt;
:defines an interval in which the module sends keepalive messages to a counter device that is conected via tcp.&lt;br /&gt;
:This attribute is ignored if the device is connected via serial port.&lt;br /&gt;
:If the device doesn&#039;t reply within a defined timeout then the module closes and tries to reopen the connection.&lt;br /&gt;
:The module tells the device when to expect the next keepalive message and the device will also close the tcp connection if it doesn&#039;t see a :keepalive message within the delay multiplied by 3&lt;br /&gt;
:The delay defaults to 10 seconds.&lt;br /&gt;
:Example: attr myCounter keepAliveDelay 30&lt;br /&gt;
&lt;br /&gt;
;keepAliveTimeout&lt;br /&gt;
:defines the timeout when wainting for a keealive reply (see keepAliveDelay) The timeout defaults to 2 seconds.&lt;br /&gt;
:Example: attr myCounter keepAliveTimeout 3&lt;br /&gt;
&lt;br /&gt;
;keepAliveRetries&lt;br /&gt;
:defines how often sending a keepalive is retried before the connection is closed and reopened.&lt;br /&gt;
:It defaults to 2.&lt;br /&gt;
:Example: attr myCounter keepAliveRetries 3&lt;br /&gt;
&lt;br /&gt;
;nextOpenDelay&lt;br /&gt;
:defines the time that the module waits before retrying to open a disconnected tcp connection.&lt;br /&gt;
:This defaults to 60 seconds.&lt;br /&gt;
:Example: attr myCounter nextOpenDelay 20&lt;br /&gt;
&lt;br /&gt;
;openTimeout&lt;br /&gt;
:defines the timeout after which tcp open gives up trying to establish a connection to the counter device. This timeout defaults to 3 seconds.&lt;br /&gt;
:Example: attr myCounter openTimeout 5&lt;br /&gt;
&lt;br /&gt;
;silentReconnect&lt;br /&gt;
:if set to 1, then it will set the loglevel for &amp;quot;disconnected&amp;quot; and &amp;quot;reappeared&amp;quot; messages to 4 instead of 3&lt;br /&gt;
:Example: attr myCounter silentReconnect 1&lt;br /&gt;
&lt;br /&gt;
;disable&lt;br /&gt;
:if set to 1 then the module closes the connection to a counter device.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Other Components]]&lt;br /&gt;
[[Kategorie:Energieverbrauchsmessung]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Template&amp;diff=31782</id>
		<title>Template</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Template&amp;diff=31782"/>
		<updated>2019-12-01T18:41:26Z</updated>

		<summary type="html">&lt;p&gt;Maista: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:template}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Einfaches Erstellen gleichartiger Devices&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=template&lt;br /&gt;
|ModForumArea=Sonstiges&lt;br /&gt;
|ModTechName=98_template.pm&lt;br /&gt;
|ModOwner=Dr. Boris Neubert ({{Link2FU|10| Forum}})&lt;br /&gt;
}}&lt;br /&gt;
Der [[template]]-Befehl vereinfacht das Erstellen gleichartiger Devices in FHEM. Ein Template-File besteht im Grunde aus FHEM Befehlen, in die Platzhalter eingefügt werden. Beim Aufruf des Template-Befehles werden die Platzhalter durch konkrete Werte ersetzt. Damit lassen sich sehr schnell ähnliche Devices (oder Kombinationen von Devices) erstellen oder ändern. Ein Template-File könnte z.B. die Definition eines Dummies inkl. mehrerer sich auf den Dummy beziehenden [[notify]] und [[at]] enthalten. Durch wiederholte Ausführung des Templates lassen sich so schnell Devices und ihre Verarbeitungslogik erstellen.&lt;br /&gt;
&lt;br /&gt;
== Template-File erstellen ==&lt;br /&gt;
Template-Files werden außerhalb FHEM erstellt und dann auf dem FHEM Server (in einem Unterverzeichnis von FHEM) abgelegt. Nutzer von [[configdb]] müssen das File zunächst importieren.&lt;br /&gt;
  &lt;br /&gt;
Derzeit (März 2017) können Template-Files noch nicht über &amp;quot;Edit Files&amp;quot; in FHEM direkt bearbeitet werden. Über einen Workaround ist dies jedoch möglich. Dateien, die in /FHEM abgelegt sind und Endungen wie z.B. .holiday oder .layout haben, werden unter &amp;quot;Edit Files&amp;quot; angezeigt und können in FHEM bearbeitet werden.&lt;br /&gt;
Das Template File kann mittels&lt;br /&gt;
:&amp;lt;code&amp;gt;template show &amp;lt;templateFile&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
angezeigt werden&lt;br /&gt;
&lt;br /&gt;
== Template-File mit Inhalt füllen ==&lt;br /&gt;
Das Template besteht aus FHEM Befehlen mit Platzhaltern, die bei der Ausführung des Template-Befehls durch konkrete Werte ersetzt werden. Ein Template könnte beispielsweise folgendermaßen definiert werden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# my Template File ./FHEM/tmpl_example.layout&lt;br /&gt;
define %name% dummy &lt;br /&gt;
&lt;br /&gt;
define di_%name% doif ([%name]) (set %device&amp;quot; on)&lt;br /&gt;
attr di_%name do always&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Gegensatz zur Kopie eines Devices mit [[copy]] ermöglicht der Template-Befehl die Definition mehrerer - von einander abhängiger - Geräte &amp;quot;in einem Rutsch&amp;quot;. Oben stehendes Beispiel ist bewusst einfach gehalten um diesen Aspekt zu verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
Für komplexere Templates bietet sich die [[Import_von_Code_Snippets|raw definition]] eines existierenden Gerätes als Ausgangspunkt an.&lt;br /&gt;
&lt;br /&gt;
== Template ausführen ==&lt;br /&gt;
Bei Ausführung des Templates werden die FHEM Befehle des Template-Files abgearbeitet. In oben definiertem Beispiel würde also ein &lt;br /&gt;
:&amp;lt;code&amp;gt;template ./FHEM/tmpl_example.layout name=myDummy device=myDevice&amp;lt;/code&amp;gt;&lt;br /&gt;
dazu führen, dass ein Dummy inkl. zugehörigem [[DOIF]] angelegt würde.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:Glossary]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Template&amp;diff=31781</id>
		<title>Template</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Template&amp;diff=31781"/>
		<updated>2019-12-01T18:41:11Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Template File mit Inhalt füllen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:template}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Einfaches Erstellen gleichartiger Devices&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=template&lt;br /&gt;
|ModForumArea=Sonstiges&lt;br /&gt;
|ModTechName=98_template.pm&lt;br /&gt;
|ModOwner=Dr. Boris Neubert ({{Link2FU|10| Forum}})&lt;br /&gt;
}}&lt;br /&gt;
Der [[template]] Befehl vereinfacht das Erstellen gleichartiger Devices in FHEM. Ein Template-File besteht im Grunde aus FHEM Befehlen, in die Platzhalter eingefügt werden. Beim Aufruf des Template-Befehles werden die Platzhalter durch konkrete Werte ersetzt. Damit lassen sich sehr schnell ähnliche Devices (oder Kombinationen von Devices) erstellen oder ändern. Ein Template-File könnte z.B. die Definition eines Dummies inkl. mehrerer sich auf den Dummy beziehenden [[notify]] und [[at]] enthalten. Durch wiederholte Ausführung des Templates lassen sich so schnell Devices und ihre Verarbeitungslogik erstellen.&lt;br /&gt;
&lt;br /&gt;
== Template-File erstellen ==&lt;br /&gt;
Template-Files werden außerhalb FHEM erstellt und dann auf dem FHEM Server (in einem Unterverzeichnis von FHEM) abgelegt. Nutzer von [[configdb]] müssen das File zunächst importieren.&lt;br /&gt;
  &lt;br /&gt;
Derzeit (März 2017) können Template-Files noch nicht über &amp;quot;Edit Files&amp;quot; in FHEM direkt bearbeitet werden. Über einen Workaround ist dies jedoch möglich. Dateien, die in /FHEM abgelegt sind und Endungen wie z.B. .holiday oder .layout haben, werden unter &amp;quot;Edit Files&amp;quot; angezeigt und können in FHEM bearbeitet werden.&lt;br /&gt;
Das Template File kann mittels&lt;br /&gt;
:&amp;lt;code&amp;gt;template show &amp;lt;templateFile&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
angezeigt werden&lt;br /&gt;
&lt;br /&gt;
== Template-File mit Inhalt füllen ==&lt;br /&gt;
Das Template besteht aus FHEM Befehlen mit Platzhaltern, die bei der Ausführung des Template-Befehls durch konkrete Werte ersetzt werden. Ein Template könnte beispielsweise folgendermaßen definiert werden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# my Template File ./FHEM/tmpl_example.layout&lt;br /&gt;
define %name% dummy &lt;br /&gt;
&lt;br /&gt;
define di_%name% doif ([%name]) (set %device&amp;quot; on)&lt;br /&gt;
attr di_%name do always&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Gegensatz zur Kopie eines Devices mit [[copy]] ermöglicht der Template-Befehl die Definition mehrerer - von einander abhängiger - Geräte &amp;quot;in einem Rutsch&amp;quot;. Oben stehendes Beispiel ist bewusst einfach gehalten um diesen Aspekt zu verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
Für komplexere Templates bietet sich die [[Import_von_Code_Snippets|raw definition]] eines existierenden Gerätes als Ausgangspunkt an.&lt;br /&gt;
&lt;br /&gt;
== Template ausführen ==&lt;br /&gt;
Bei Ausführung des Templates werden die FHEM Befehle des Template-Files abgearbeitet. In oben definiertem Beispiel würde also ein &lt;br /&gt;
:&amp;lt;code&amp;gt;template ./FHEM/tmpl_example.layout name=myDummy device=myDevice&amp;lt;/code&amp;gt;&lt;br /&gt;
dazu führen, dass ein Dummy inkl. zugehörigem [[DOIF]] angelegt würde.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:Glossary]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Template&amp;diff=31780</id>
		<title>Template</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Template&amp;diff=31780"/>
		<updated>2019-12-01T18:38:25Z</updated>

		<summary type="html">&lt;p&gt;Maista: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:template}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Einfaches Erstellen gleichartiger Devices&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=template&lt;br /&gt;
|ModForumArea=Sonstiges&lt;br /&gt;
|ModTechName=98_template.pm&lt;br /&gt;
|ModOwner=Dr. Boris Neubert ({{Link2FU|10| Forum}})&lt;br /&gt;
}}&lt;br /&gt;
Der [[template]] Befehl vereinfacht das Erstellen gleichartiger Devices in FHEM. Ein Template-File besteht im Grunde aus FHEM Befehlen, in die Platzhalter eingefügt werden. Beim Aufruf des Template-Befehles werden die Platzhalter durch konkrete Werte ersetzt. Damit lassen sich sehr schnell ähnliche Devices (oder Kombinationen von Devices) erstellen oder ändern. Ein Template-File könnte z.B. die Definition eines Dummies inkl. mehrerer sich auf den Dummy beziehenden [[notify]] und [[at]] enthalten. Durch wiederholte Ausführung des Templates lassen sich so schnell Devices und ihre Verarbeitungslogik erstellen.&lt;br /&gt;
&lt;br /&gt;
== Template-File erstellen ==&lt;br /&gt;
Template-Files werden außerhalb FHEM erstellt und dann auf dem FHEM Server (in einem Unterverzeichnis von FHEM) abgelegt. Nutzer von [[configdb]] müssen das File zunächst importieren.&lt;br /&gt;
  &lt;br /&gt;
Derzeit (März 2017) können Template-Files noch nicht über &amp;quot;Edit Files&amp;quot; in FHEM direkt bearbeitet werden. Über einen Workaround ist dies jedoch möglich. Dateien, die in /FHEM abgelegt sind und Endungen wie z.B. .holiday oder .layout haben, werden unter &amp;quot;Edit Files&amp;quot; angezeigt und können in FHEM bearbeitet werden.&lt;br /&gt;
Das Template File kann mittels&lt;br /&gt;
:&amp;lt;code&amp;gt;template show &amp;lt;templateFile&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
angezeigt werden&lt;br /&gt;
&lt;br /&gt;
== Template File mit Inhalt füllen ==&lt;br /&gt;
Das Template besteht aus FHEM Befehlen mit Platzhaltern, die bei der Ausführung des Template-Befehls durch konkrete Werte ersetzt werden. Ein Template könnte beispielsweise folgendermaßen definiert werden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# my Template File ./FHEM/tmpl_example.layout&lt;br /&gt;
define %name% dummy &lt;br /&gt;
&lt;br /&gt;
define di_%name% doif ([%name]) (set %device&amp;quot; on)&lt;br /&gt;
attr di_%name do always&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Gegensatz zur Kopie eines Devices mit [[copy]] ermöglicht der Template-Befehl die Definition mehrerer - von einander abhängiger - Geräte &amp;quot;in einem Rutsch&amp;quot;. Oben stehendes Beispiel ist bewusst einfach gehalten um diesen Aspekt zu verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
Für komplexere Templates bietet sich die [[Import_von_Code_Snippets|raw definition]] eines existierenden Gerätes als Ausgangspunkt an.&lt;br /&gt;
&lt;br /&gt;
== Template ausführen ==&lt;br /&gt;
Bei Ausführung des Templates werden die FHEM Befehle des Template-Files abgearbeitet. In oben definiertem Beispiel würde also ein &lt;br /&gt;
:&amp;lt;code&amp;gt;template ./FHEM/tmpl_example.layout name=myDummy device=myDevice&amp;lt;/code&amp;gt;&lt;br /&gt;
dazu führen, dass ein Dummy inkl. zugehörigem [[DOIF]] angelegt würde.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:Glossary]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Template&amp;diff=31779</id>
		<title>Template</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Template&amp;diff=31779"/>
		<updated>2019-12-01T18:37:34Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Template File erstellen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:template}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Einfaches Erstellen gleichartiger Devices&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=template&lt;br /&gt;
|ModForumArea=Sonstiges&lt;br /&gt;
|ModTechName=98_template.pm&lt;br /&gt;
|ModOwner=Dr. Boris Neubert ({{Link2FU|10| Forum}})&lt;br /&gt;
}}&lt;br /&gt;
Der [[template]] Befehl vereinfacht das Erstellen gleichartiger Devices in FHEM. Ein Template File besteht im Grunde aus FHEM Befehlen, in die Platzhalter eingefügt werden. Beim Aufruf des Template-Befehles werden die Platzhalter durch konkrete Werte ersetzt. Damit lassen sich sehr schnell ähnliche Devices (oder Kombinationen von Devices) erstellen oder ändern. Ein Template File könnte z.B. die Definition eines Dummies inkl. mehrerer sich auf den Dummy beziehenden [[notify]] und [[at]] enthalten. Durch wiederholte Ausführung des Templates lassen sich so schnell Devices und ihre Verarbeitungslogik erstellen.&lt;br /&gt;
&lt;br /&gt;
== Template-File erstellen ==&lt;br /&gt;
Template-Files werden außerhalb FHEM erstellt und dann auf dem FHEM Server (in einem Unterverzeichnis von FHEM) abgelegt. Nutzer von [[configdb]] müssen das File zunächst importieren.&lt;br /&gt;
  &lt;br /&gt;
Derzeit (März 2017) können Template-Files noch nicht über &amp;quot;Edit Files&amp;quot; in FHEM direkt bearbeitet werden. Über einen Workaround ist dies jedoch möglich. Dateien, die in /FHEM abgelegt sind und Endungen wie z.B. .holiday oder .layout haben, werden unter &amp;quot;Edit Files&amp;quot; angezeigt und können in FHEM bearbeitet werden.&lt;br /&gt;
Das Template File kann mittels&lt;br /&gt;
:&amp;lt;code&amp;gt;template show &amp;lt;templateFile&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
angezeigt werden&lt;br /&gt;
&lt;br /&gt;
== Template File mit Inhalt füllen ==&lt;br /&gt;
Das Template besteht aus FHEM Befehlen mit Platzhaltern, die bei der Ausführung des Template-Befehls durch konkrete Werte ersetzt werden. Ein Template könnte beispielsweise folgendermaßen definiert werden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# my Template File ./FHEM/tmpl_example.layout&lt;br /&gt;
define %name% dummy &lt;br /&gt;
&lt;br /&gt;
define di_%name% doif ([%name]) (set %device&amp;quot; on)&lt;br /&gt;
attr di_%name do always&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Gegensatz zur Kopie eines Devices mit [[copy]] ermöglicht der Template-Befehl die Definition mehrerer - von einander abhängiger - Geräte &amp;quot;in einem Rutsch&amp;quot;. Oben stehendes Beispiel ist bewusst einfach gehalten um diesen Aspekt zu verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
Für komplexere Templates bietet sich die [[Import_von_Code_Snippets|raw definition]] eines existierenden Gerätes als Ausgangspunkt an.&lt;br /&gt;
&lt;br /&gt;
== Template ausführen ==&lt;br /&gt;
Bei Ausführung des Templates werden die FHEM Befehle des Template-Files abgearbeitet. In oben definiertem Beispiel würde also ein &lt;br /&gt;
:&amp;lt;code&amp;gt;template ./FHEM/tmpl_example.layout name=myDummy device=myDevice&amp;lt;/code&amp;gt;&lt;br /&gt;
dazu führen, dass ein Dummy inkl. zugehörigem [[DOIF]] angelegt würde.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:Glossary]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Template&amp;diff=31778</id>
		<title>Template</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Template&amp;diff=31778"/>
		<updated>2019-12-01T18:37:12Z</updated>

		<summary type="html">&lt;p&gt;Maista: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:template}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Einfaches Erstellen gleichartiger Devices&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=template&lt;br /&gt;
|ModForumArea=Sonstiges&lt;br /&gt;
|ModTechName=98_template.pm&lt;br /&gt;
|ModOwner=Dr. Boris Neubert ({{Link2FU|10| Forum}})&lt;br /&gt;
}}&lt;br /&gt;
Der [[template]] Befehl vereinfacht das Erstellen gleichartiger Devices in FHEM. Ein Template File besteht im Grunde aus FHEM Befehlen, in die Platzhalter eingefügt werden. Beim Aufruf des Template-Befehles werden die Platzhalter durch konkrete Werte ersetzt. Damit lassen sich sehr schnell ähnliche Devices (oder Kombinationen von Devices) erstellen oder ändern. Ein Template File könnte z.B. die Definition eines Dummies inkl. mehrerer sich auf den Dummy beziehenden [[notify]] und [[at]] enthalten. Durch wiederholte Ausführung des Templates lassen sich so schnell Devices und ihre Verarbeitungslogik erstellen.&lt;br /&gt;
&lt;br /&gt;
== Template File erstellen ==&lt;br /&gt;
Template Files werden außerhalb FHEM erstellt und dann auf dem FHEM Server (in einem Unterverzeichnis von FHEM) abgelegt. Nutzer von [[configdb]] müssen das File zunächst importieren.&lt;br /&gt;
  &lt;br /&gt;
Derzeit (März 2017) können Template-Files noch nicht über &amp;quot;Edit Files&amp;quot; in FHEM direkt bearbeitet werden. Über einen Workaround ist dies jedoch möglich. Dateien, die in /FHEM abgelegt sind und Endungen wie z.B. .holiday oder .layout haben, werden unter &amp;quot;Edit Files&amp;quot; angezeigt und können in FHEM bearbeitet werden.&lt;br /&gt;
Das Template File kann mittels&lt;br /&gt;
:&amp;lt;code&amp;gt;template show &amp;lt;templateFile&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
angezeigt werden&lt;br /&gt;
&lt;br /&gt;
== Template File mit Inhalt füllen ==&lt;br /&gt;
Das Template besteht aus FHEM Befehlen mit Platzhaltern, die bei der Ausführung des Template-Befehls durch konkrete Werte ersetzt werden. Ein Template könnte beispielsweise folgendermaßen definiert werden.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# my Template File ./FHEM/tmpl_example.layout&lt;br /&gt;
define %name% dummy &lt;br /&gt;
&lt;br /&gt;
define di_%name% doif ([%name]) (set %device&amp;quot; on)&lt;br /&gt;
attr di_%name do always&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Gegensatz zur Kopie eines Devices mit [[copy]] ermöglicht der Template-Befehl die Definition mehrerer - von einander abhängiger - Geräte &amp;quot;in einem Rutsch&amp;quot;. Oben stehendes Beispiel ist bewusst einfach gehalten um diesen Aspekt zu verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
Für komplexere Templates bietet sich die [[Import_von_Code_Snippets|raw definition]] eines existierenden Gerätes als Ausgangspunkt an.&lt;br /&gt;
&lt;br /&gt;
== Template ausführen ==&lt;br /&gt;
Bei Ausführung des Templates werden die FHEM Befehle des Template-Files abgearbeitet. In oben definiertem Beispiel würde also ein &lt;br /&gt;
:&amp;lt;code&amp;gt;template ./FHEM/tmpl_example.layout name=myDummy device=myDevice&amp;lt;/code&amp;gt;&lt;br /&gt;
dazu führen, dass ein Dummy inkl. zugehörigem [[DOIF]] angelegt würde.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:Glossary]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=ESPEasy&amp;diff=31659</id>
		<title>ESPEasy</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=ESPEasy&amp;diff=31659"/>
		<updated>2019-11-08T22:59:43Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* userSetCmds */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Modul&lt;br /&gt;
|ModPurpose=Steuerung eines Espressif ESP8266 WLAN-SoC&lt;br /&gt;
|ModType=d&lt;br /&gt;
|ModCmdRef= &lt;br /&gt;
|ModForumArea=Bastelecke/ESP8266&lt;br /&gt;
|ModFTopic=55728&lt;br /&gt;
|ModTechName=34_ESPEasy.pm&lt;br /&gt;
|ModOwner={{Link2FU|7465|dev0}}&lt;br /&gt;
}}&lt;br /&gt;
Dieser Wiki-Artikel soll und kann die {{Link2CmdRef|Anker=ESPEasy|Lang=en|Label=ESPEasy Modul-Dokumentation}}(aka FHEM Command Reference) nicht ersetzen, sondern ergänzt die Dokumentation nur um ein paar Informationen.&lt;br /&gt;
&lt;br /&gt;
== Grundlegende ESP Easy Einstellungen ==&lt;br /&gt;
&lt;br /&gt;
Diese Einstellungen sind in der Weboberfläche des ESP vorzunehmen und bewirken u.a., dass für jedes ESPEasy-Device ein FHEM Device angelegt wird. Das kann bspw. für einen ESP sinnvoll sein, der Relays über GPIOs schalten soll (ESPEasy Device-Type &#039;&#039;Switch Input&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
*Es muss ein einmaliger ESP Devicename vergeben werden (&#039;&#039;Config&#039;&#039; -&amp;gt; &#039;&#039;Main Settings&#039;&#039; -&amp;gt;&#039;&#039;Name&#039;&#039;)&lt;br /&gt;
*Die verwendeten ESP Easy Devices sollten einen ESP-weit einmaligen Namen erhalten (&#039;&#039;Device&#039;&#039; -&amp;gt; &#039;&#039;Edit&#039;&#039; -&amp;gt; &#039;&#039;Task Settings&#039;&#039; -&amp;gt; &#039;&#039;Name&#039;&#039;). Ist dieser Name nicht eindeutig oder wird nicht vergeben, dann gibt es u.a. Probleme mit ESP Easy Rules [link].&lt;br /&gt;
*Jeder Wert, der gesendet werden soll, benötigt ebenfalls einen Namen, der in diesem ESP Device einmalig sein muss (&#039;&#039;Device&#039;&#039; -&amp;gt; &#039;&#039;Edit&#039;&#039; -&amp;gt; &#039;&#039;Optional Settings&#039;&#039; -&amp;gt; &#039;&#039;Value Name&#039;&#039;)&lt;br /&gt;
*Soll dieser Wert nun automatisch in einem Interval von x Sekunden (an FHEM) gesendet werden, dann muss noch das &#039;&#039;Delay&#039;&#039; (&#039;&#039;Device&#039;&#039; -&amp;gt; &#039;&#039;Edit&#039;&#039; -&amp;gt; &#039;&#039;Task Settings&#039;&#039; -&amp;gt; &#039;&#039;Delay&#039;&#039;) angegeben und die Option &#039;&#039;Send Data&#039;&#039; (&#039;&#039;Device&#039;&#039; -&amp;gt; &#039;&#039;Edit&#039;&#039; -&amp;gt; &#039;&#039;Task Settings&#039;&#039; -&amp;gt; &#039;&#039;Send Data&#039;&#039;) aktiviert werden. Die Option &#039;&#039;Send Boot State&#039;&#039; ist an dieser Stelle ebenfalls sinnvoll.&lt;br /&gt;
&lt;br /&gt;
=== Attribut combineDevices ===&lt;br /&gt;
&lt;br /&gt;
Wenn das oben genannte Verhalten (ein FHEM Device pro ESP Easy Device) nicht gewünscht ist, dann kann man mittels des Attributes &#039;&#039;combineDevices&#039;&#039; der {{Link2CmdRef|Anker=ESPEasy_bridge_define|Lang=en|Label=ESPEasy Bridge}} einstellen, ob die ESP Easy Devices eines einzelnen ESPs in ein FHEM Device zusammengeführt werden sollen.&lt;br /&gt;
Diese Funktionalität kann man global einschalten, indem man dem Attribut &#039;&#039;combineDevices&#039;&#039; den Wert &#039;&#039;1&#039;&#039; gibt.&lt;br /&gt;
&lt;br /&gt;
Will man nur von bestimmten ESPs die Devices zusammen fassen, dann kann man eine komma-getrennte Liste der ESPs angeben. Die Liste kann aus ESP Namen, IP Adressen und/oder Netzwerkbereichen bestehen. Netzwerkbereiche können mit einer Netzmaske in dotted decimal (/255.255.255.0) oder in bitmask (/24) Schreibweise angegeben werden. Hostnamen und FQDNs werden nicht unterstützt.&lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
 attr &amp;lt;esp&amp;gt; combineDevices ESP1,ESP2&lt;br /&gt;
 attr &amp;lt;esp&amp;gt; combineDevices 10.0.0.148,10.0.0.149&lt;br /&gt;
 attr &amp;lt;esp&amp;gt; combineDevices 192.168.124.0/24&lt;br /&gt;
 attr &amp;lt;esp&amp;gt; combineDevices 192.168.124.0/255.255.255.0&lt;br /&gt;
 attr &amp;lt;esp&amp;gt; combineDevices ESP1,ESP2,10.0.0.0/8,192.168.0.0/255.255.0.0&lt;br /&gt;
&lt;br /&gt;
IPv6 Adressen/Bereiche werden zwar von FHEM, allerdings zur Zeit noch nicht von der öffentlichen ESP Easy Distribution unterstützt.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
 attr &amp;lt;esp&amp;gt; combineDevices 2001:1a50:50a8::148,2001:abcd:efff::/48&lt;br /&gt;
&lt;br /&gt;
== Presence Erkennung ==&lt;br /&gt;
Die &amp;quot;Presence Detection&amp;quot;, also die Erkennung, ob ein ESP noch Daten sendet, wurde anhand des Alters der empfangenen (Sensor-)Werte realisiert. Vereinfacht gesagt: Werden keine Readings mehr innerhalb von x Sekunden empfangen (siehe Device-Attribut &#039;&#039;Interval&#039;&#039;), wird das FHEM Device als &amp;quot;absent&amp;quot; gekennzeichnet. Das hat den Vorteil, dass auch ESP Easy Devices, die zwischen dem Senden von Daten in den so genannten Deep Sleep Modus gehen, erkannt werden können.&lt;br /&gt;
&lt;br /&gt;
Das Attribut &#039;&#039;Interval&#039;&#039; gibt unter anderem vor, in welchem zeitlichen Abstand Werte vom ESP erwartet werden, damit der ESP als &amp;quot;present&amp;quot; (und nicht absent) markiert wird.&lt;br /&gt;
&lt;br /&gt;
Wenn ein ESP Easy Device Werte alle 60 Sekunden sendet (Option &#039;&#039;Delay&#039;&#039; in der ESP Easy Device GUI) und das FHEM Device Interval auf 60 gesetzt ist, dann würde das Device-Reading &amp;quot;presence&amp;quot; auf &amp;quot;absent&amp;quot; wechseln, wenn innerhalb von 60-120 Sekunden keine Werte empfangen werden.&lt;br /&gt;
&lt;br /&gt;
Also wäre zum Beispiel die ESP Easy Firmware so zu konfigurieren, dass mindestens ein Wert alle 60 Sekunden gesendet wird. Das Interval-Attribut des entsprechenden FHEM ESPEasy Device müsste ebenfalls auf 60 (default) gesetzt werden. Ein paar Sekunden Toleranz sind im ESPEasy Modul eingebaut.&lt;br /&gt;
&lt;br /&gt;
Wenn man kein ESP Easy Device hat, das Daten an FHEM sendet, dann kann man zusätzlich einen der &amp;quot;System Info&amp;quot; Werte senden lassen und &#039;&#039;combineDevices&#039;&#039; für diesen ESP aktivieren. Es reicht nämlich, wenn ein Reading regelmäßig aktualisiert wird.&lt;br /&gt;
&lt;br /&gt;
Wenn die Presence Erkennung nicht genutzt werden soll, dann muss das Attribut &#039;&#039;presenceCheck&#039;&#039; auf 0 gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
== Sicherheit ==&lt;br /&gt;
&lt;br /&gt;
Wenn eine ESPEasy Bridge in FHEM eingerichtet wurde, dann werden Verbindungen nur von IP Adressen aus [https://tools.ietf.org/html/rfc1918 privaten Bereichen] zugelassen.&lt;br /&gt;
&lt;br /&gt;
Wenn ESP Easy Geräte außerhalb dieser Bereiche Daten an FHEM senden (z.B. über das Internet), dann muss das in der ESPEasy Bridge konfiguriert werden, andernfalls wird die Verbindung abgewiesen.&lt;br /&gt;
&lt;br /&gt;
Einerseits muss die IP Adresse bzw. der IP Bereich erlaubt (Attribute &#039;&#039;allowedIPs&#039;&#039;, &#039;&#039;deniedIPs&#039;&#039;), andererseits die Authentifizierung über &amp;quot;Basic Auth&amp;quot; in der ESPEasy Bridge eingerichtet werden.&lt;br /&gt;
Die Authentifizierung wird über das Attribut &#039;&#039;authentication&#039;&#039; eingeschaltet. Die Benutzerdaten für die Authentifizierung werden über die Set-Befehle &#039;&#039;user&#039;&#039; und &#039;&#039;pass&#039;&#039; der Bridge eingegeben&lt;br /&gt;
{{Hinweis|Hinweis: Username und Passwort werden unverschlüsselt in ./FHEM/FhemUtils/uniqueID gespeichert.}}&lt;br /&gt;
&lt;br /&gt;
=== Attribut authentication ===&lt;br /&gt;
Beispiel:&lt;br /&gt;
 set &amp;lt;espbridge&amp;gt; user MeinUserName&lt;br /&gt;
 set &amp;lt;espbridge&amp;gt; pass sehrgeheim&lt;br /&gt;
 attr &amp;lt;espbridge&amp;gt; authentication 1&lt;br /&gt;
&lt;br /&gt;
=== Attribute allowedIPs / deniedIPs ===&lt;br /&gt;
Beispiel:&lt;br /&gt;
 attr &amp;lt;espbridge&amp;gt; allowedIPs 192.0.2.0/24   # erlaubt ist 192.0.2.0 bis 192.0.2.255&lt;br /&gt;
 attr &amp;lt;espbridge&amp;gt; deniedIPs 192.0.2.0/29    # ausgeschlossen werden aber die IPs von 192.0.2.0 bis 192.0.2.7&lt;br /&gt;
&lt;br /&gt;
Das Attribut &#039;&#039;deniedIPs&#039;&#039; hat Vorrang vor &#039;&#039;allowedIPs&#039;&#039;. Das bedeutet, dass verbotene IPs niemals eine Verbindung aufbauen können, auch wenn sie vorher erlaubt wurden.&lt;br /&gt;
&lt;br /&gt;
Regular Expressions sind können ebenfalls verwendet werden:&lt;br /&gt;
 attr &amp;lt;espbridge&amp;gt; allowedIPs 192.0.2.1([0-4][0-9]|50)     # erlaubt IP von 192.168.30.100 bis 192.168.30.150&lt;br /&gt;
&lt;br /&gt;
Alle Details dazu sind in der {{Link2CmdRef|Anker=ESPEasy_bridge_attr_allowedips|Lang=en|Label=Command Reference}} beschrieben.&lt;br /&gt;
&lt;br /&gt;
== Erweiterte Beispiele==&lt;br /&gt;
Hier ein paar Beispiele für unterschiedlichste Anwendungsfälle&lt;br /&gt;
&lt;br /&gt;
===  Schalter in FHEMWEB mit devStateIcons ===&lt;br /&gt;
Beispiel für GPIO 12:&lt;br /&gt;
 attr &amp;lt;ESP&amp;gt; stateFormat {ReadingsVal($name,&amp;quot;presence&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;absent&amp;quot; ? &amp;quot;absent&amp;quot; : ReadingsVal($name,&amp;quot;GPIO12&amp;quot;,&amp;quot;&amp;quot;)}&lt;br /&gt;
 attr &amp;lt;ESP&amp;gt; devStateIcon on:ios-on-green:off off:ios-off:on absent:10px-kreis-rot:statusRequest&lt;br /&gt;
 attr &amp;lt;ESP&amp;gt; eventMap /gpio 12 on:on/gpio 12 off:off/&lt;br /&gt;
 attr &amp;lt;ESP&amp;gt; webCmd :&lt;br /&gt;
&lt;br /&gt;
=== on-for-timer und off-for-timer ===&lt;br /&gt;
Beispiel für GPIO 15:&lt;br /&gt;
 attr &amp;lt;ESP&amp;gt; /longpulse 15 on:on-for-time:slider,0,1,60/longpulse 15 off:off-for-time:slider,0,1,60/&lt;br /&gt;
&lt;br /&gt;
=== (on|off)-for-timer und devStateIcons ===&lt;br /&gt;
Beispiel für GPIO 15:&lt;br /&gt;
 attr &amp;lt;ESP&amp;gt; eventMap /longpulse 15 on:on-for-time:slider,0,1,60/longpulse 15 off:off-for-time:slider,0,1,60/gpio 15 on:on/gpio 15 off:off/&lt;br /&gt;
&lt;br /&gt;
=== userSetCmds ===&lt;br /&gt;
Mithilfe des Attributes userSetCmds kann man:&lt;br /&gt;
*Einzelne ESP Easy Befehle nachrüsten&lt;br /&gt;
*Eigene oder nicht unterstützte Plugins integrieren&lt;br /&gt;
*Bereits integrierte Befehle verändern&lt;br /&gt;
*Befehle einzelner Plugins mappen: Statt &#039;set &amp;lt;dev&amp;gt; plugin_a on&#039; kann man so &#039;set &amp;lt;dev&amp;gt; on&#039; verwenden. Das wird z.B. benötigt, um FHEMs setExtentions oder auch um FHEMWEB Widgets nutzen zu können.&lt;br /&gt;
&lt;br /&gt;
Die generelle Syntax des Attributes ist ein Perl Hash, der die Eigenschaften des ESP Easy Befehls/Plugins beschreibt.&lt;br /&gt;
Folgende Eigenschaften (Keys) gibt es:&lt;br /&gt;
*args: Anzahl der benötigten Parameter. Default: 0&lt;br /&gt;
*url: Die aufzurufende URL. Default: /control?cmd=&lt;br /&gt;
*widget: Das FHEMWEB Widget, dass beim FHEMWEB Setter des Befehls verwendet werden soll. Default: keines&lt;br /&gt;
*usage: Diese Zeichenkette wird zum einen angezeigt, wenn ein falscher oder zu wenige Parameter beim Befehlsaufruf angeben wurden. Zum anderen haben folgende Zeichenketten eine besondere Bedeutung:&lt;br /&gt;
**&amp;lt;0|1|off|on&amp;gt;: Innerhalb des FHEM Befehl kann on/off statt 0/1 angegeben werden. An die ESP Easy Firmware wird 0/1 gesendet.&lt;br /&gt;
**&amp;lt;pin&amp;gt;: Bei dem Paramater handelt es sin um einen GPIO Port. Aliasnamen können verwendet werden. Siehe: get &amp;lt;dev&amp;gt; pinMap&lt;br /&gt;
**&amp;lt;text&amp;gt;: Dieser Paramter wird url encoded an die ESP Easy Firmware gesendet. Wird für die Ausgabe auf (O)led Displays benötigt.&lt;br /&gt;
*cmds: Diese Eigenschaft (key) muss ebenfalls ein Perl Hash sein. Dieser Key definiert die Unterbefehle des Plugins. Alle oben genannten Eigenschaften (Keys) können benutzt werden. Nur der Key &#039;url&#039; kann nicht angegeben werden, da in diesem Fall die URL des Plugins verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Ein einzelner neuer Befehl &#039;myCmd1&#039;:&lt;br /&gt;
 attr &amp;lt;dev&amp;gt; userSetCmds ( myCmd1 =&amp;gt; {} )&lt;br /&gt;
&lt;br /&gt;
Ein einzelner neuer Befehl &#039;myCmd1&#039;. Der erste Paramater enthält einen GPIO Port, der durch Aliasnamen ersetzt werden kann. Der zweite Paramater kann als on/off geschrieben werden, gesendet wird aber 1/0:&lt;br /&gt;
 attr &amp;lt;dev&amp;gt; userSetCmds ( myCmd1 =&amp;gt; { usage =&amp;gt; &amp;quot;&amp;lt;pin&amp;gt; &amp;lt;0|1|off|on&amp;gt;&amp;quot; } )&lt;br /&gt;
&lt;br /&gt;
Zwei neue Befehle, mit allen default Werten:&lt;br /&gt;
 attr &amp;lt;dev&amp;gt; userSetCmds ( myCmd1 =&amp;gt; {}, myCmd2 =&amp;gt; {} )&lt;br /&gt;
&lt;br /&gt;
Zwei neue Befehle, der zweite Befehl verwendet eine abweichende URL:&lt;br /&gt;
 attr &amp;lt;dev&amp;gt; userSetCmds ( myCmd1 =&amp;gt; {}, myCmd2 =&amp;gt; { url =&amp;gt; &amp;quot;/?cmd=&amp;quot; } )&lt;br /&gt;
&lt;br /&gt;
Beispiel für das fiktive Plugin &#039;LED&#039; mit den Unterbefehlen &#039;rgb&#039; und &#039;ct&#039;. Die Unterbefehle &#039;rgb&#039; und &#039;ct&#039; können ohne Angabe des Pluginnamens &#039;LED&#039; verwendet werden. Zusätzlich werden in der FHEMWEB-Ansicht die Slider Widgets hsv/ct verwendet:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
attr &amp;lt;dev&amp;gt; userSetCmds (&lt;br /&gt;
  LED =&amp;gt; {&lt;br /&gt;
    args  =&amp;gt; 2,&lt;br /&gt;
    url   =&amp;gt; &amp;quot;/control?cmd=&amp;quot;,&lt;br /&gt;
    usage =&amp;gt; &amp;quot;&amp;lt;rgb|ct&amp;gt; &amp;lt;rrggbb|colortemp&amp;gt;&amp;quot;,&lt;br /&gt;
    cmds  =&amp;gt; {&lt;br /&gt;
      rgb =&amp;gt; { args =&amp;gt; 1, usage =&amp;gt; &amp;quot;&amp;lt;rrggbb&amp;gt;&amp;quot;,    widget =&amp;gt; &amp;quot;colorpicker,HSV&amp;quot; },&lt;br /&gt;
      ct  =&amp;gt; { args =&amp;gt; 1, usage =&amp;gt; &amp;quot;&amp;lt;colortemp&amp;gt;&amp;quot;, widget =&amp;gt; &amp;quot;colorpicker,CT,2000,10,4000&amp;quot; }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
) &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== useSetExtensions ===&lt;br /&gt;
Mithilfe der FHEM setExtentions kann man die Befehle on-for-timer, off-for-timer, on-till, off-till, blink, intervals, toggle, etc nutzen. Im Gegensatz zu den ESP Easy Firmware Befehlen &#039;pulse&#039;, &#039;longpulse&#039; und &#039;longpulse_ms&#039; laufen die Timer nicht innerhalb der ESP Easy Firmware, sondern in FHEM. Mit allen Vor- und Nachteilen.&lt;br /&gt;
Um die setExtensions nutzen zu können muss das Attribut &#039;useExtensions&#039; auf 1 gesetzt sein. Weiterhin müssen die Befehle &#039;on&#039; und &#039;off&#039;, für das entsprechende Device, verfügbar sein. Das kann man auf verschiedene Weisen realisieren:&lt;br /&gt;
==== setExtensions mit eventMap ====&lt;br /&gt;
In diesem Beispiel wird der Befehl &#039;set &amp;lt;dev&amp;gt; GPIO 15 on&#039; mithilfe des globalen Attributs &#039;eventMap&#039; auf den Befehl &#039;set &amp;lt;dev&amp;gt; on&#039; gemappt.  Gleiches gilt für &#039;off&#039;.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
attr &amp;lt;dev&amp;gt; useSetExtensions 1&lt;br /&gt;
attr &amp;lt;dev&amp;gt; eventMap /gpio 15 on:^on$/gpio 15 off:^off$/&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==== setExtentions mit userSetCmds ====&lt;br /&gt;
In diesem Beispiel wird nicht das globale Attribut &#039;eventMap&#039; benutzt, sondern das ESPEasy Attribut &#039;userSetCmds&#039;, um die &#039;on&#039; und &#039;off&#039; Befehle bereitzustellen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
attr &amp;lt;dev&amp;gt; useSetExtensions 1&lt;br /&gt;
attr &amp;lt;dev&amp;gt; userSetCmds ( on =&amp;gt; {url=&amp;gt;&amp;quot;/control?cmd=gpio,15,1&amp;quot;, args =&amp;gt; -1}, off =&amp;gt; {url=&amp;gt;&amp;quot;/control?cmd=gpio,15,0&amp;quot;, args =&amp;gt; -1} &lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Logging==&lt;br /&gt;
===ESPEasy Bridge===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
2018.02.10 08:48:06.197 4: Connection accepted from eb_10.0.0.148_25654&lt;br /&gt;
2018.02.10 08:48:06.199 4: ESPEasy eb_10.0.0.148_25654: Peer address accepted&lt;br /&gt;
2018.02.10 08:48:06.199 5: ESPEasy eb_10.0.0.148_25654: Received header: {&#039;Content-Length&#039; =&amp;gt; &#039;298&#039;,&#039;Authorization&#039; =&amp;gt; &#039;Basic ***** &#039;,&#039;Host&#039; =&amp;gt; &#039;10.0.0.53&#039;,&#039;Connection&#039; =&amp;gt; &#039;close&#039;}&lt;br /&gt;
2018.02.10 08:48:06.199 5: ESPEasy eb_10.0.0.148_25654: Received content: {&amp;quot;module&amp;quot;:&amp;quot;ESPEasy&amp;quot;,&amp;quot;version&amp;quot;:&amp;quot;1.02&amp;quot;,&amp;quot;data&amp;quot;:{&amp;quot;ESP&amp;quot;:{&amp;quot;name&amp;quot;:&amp;quot;BA_SEN1&amp;quot;,&amp;quot;unit&amp;quot;:4,&amp;quot;version&amp;quot;:9,&amp;quot;build&amp;quot;:137,&amp;quot;sleep&amp;quot;:0,&amp;quot;ip&amp;quot;:&amp;quot;10.0.0.148&amp;quot;},&amp;quot;SENSOR&amp;quot;:{&amp;quot;0&amp;quot;:{&amp;quot;deviceName&amp;quot;:&amp;quot;DHT22&amp;quot;,&amp;quot;valueName&amp;quot;:&amp;quot;temperature&amp;quot;,&amp;quot;type&amp;quot;:2,&amp;quot;value&amp;quot;:&amp;quot;21.5&amp;quot;},&amp;quot;1&amp;quot;:{&amp;quot;deviceName&amp;quot;:&amp;quot;DHT22&amp;quot;,&amp;quot;valueName&amp;quot;:&amp;quot;humidity&amp;quot;,&amp;quot;type&amp;quot;:2,&amp;quot;value&amp;quot;:&amp;quot;12.2&amp;quot;}}}}&lt;br /&gt;
2018.02.10 08:48:06.200 4: ESPEasy eb_10.0.0.148_25654: Basic authentication accepted&lt;br /&gt;
2018.02.10 08:48:06.200 4: ESPEasy eb_10.0.0.148_25654: Send http close &#039;200 OK&#039;&lt;br /&gt;
2018.02.10 08:48:06.202 4: ESPEasy eb_10.0.0.148_25654: Src:&#039;BA_SEN1&#039;/&#039;DHT22&#039; =&amp;gt; ident:BA_SEN1 dev:ESPEasy_BA_SEN1 combinedDevice:1&lt;br /&gt;
2018.02.10 08:48:06.202 5: eb: dispatch BA_SEN1::10.0.0.148::1::0::1::i||unit||4||0|||i||sleep||0||0|||i||build||137||0|||i||version||9||0|||r||temperature||21.5||2|||r||humidity||12.2||2&lt;br /&gt;
2018.02.10 08:48:06.209 4: ESPEasy eb_10.0.0.148_25654: Closing tcp session.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Detail bedeuten die Logeinträge:&lt;br /&gt;
&lt;br /&gt;
;Connection accepted from eb_10.0.0.148_25654&lt;br /&gt;
:Eine TCP Verbindung wurde vom ESP (IP: 10.0.0.148, source port: 25654) zur Bridge &amp;quot;eb&amp;quot; aufgebaut.&lt;br /&gt;
&lt;br /&gt;
;ESPEasy eb_10.0.0.148_25654&lt;br /&gt;
:Es wurde ein temporäres ESPEasy Bridge Devices angelegt, das Daten von der IP 10.0.0.148 und Quellport 25654 empfängt.&lt;br /&gt;
&lt;br /&gt;
;Peer address accepted&lt;br /&gt;
:Die IP Adresse des ESP wurde akzeptiert und die empfangenen Daten werden nun verarbeitet. Wenn die IP Adresse nicht akzeptiert wird, dann wird &#039;&#039;&#039;Peer address rejected&#039;&#039;&#039; gelogged.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;Received header: {&#039;Content-Length&#039; =&amp;gt; &#039;298&#039;,&#039;Authorization&#039; =&amp;gt; &#039;Basic ***** &#039;,&#039;Host&#039; =&amp;gt; &#039;10.0.0.53&#039;,&#039;Connection&#039; =&amp;gt; &#039;close&#039;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Diese &#039;&#039;received header&#039;&#039; Zeile enthält die Daten des Headers, die via HTTP vom ESP empfangen werden. Ein eventuell vorhandenes Passwort wird maskiert.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;Received content: {&amp;quot;module&amp;quot;:&amp;quot;ESPEasy&amp;quot;,&amp;quot;version&amp;quot;:&amp;quot;1.02&amp;quot;,&amp;quot;data&amp;quot;:&amp;quot;ESP&amp;quot;:&amp;quot;name&amp;quot;:&amp;quot;BA_SEN1&amp;quot;,&amp;quot;unit&amp;quot;:4,&amp;quot;version&amp;quot;:9,&amp;quot;build&amp;quot;:137,&amp;quot;sleep&amp;quot;:0,&amp;quot;ip&amp;quot;:&amp;quot;10.0.0.148&amp;quot;},&amp;quot;SENSOR&amp;quot;:&amp;quot;0&amp;quot;:{&amp;quot;deviceName&amp;quot;:&amp;quot;DHT22&amp;quot;,&amp;quot;valueName&amp;quot;:&amp;quot;temperature&amp;quot;,&amp;quot;type&amp;quot;:2,&amp;quot;value&amp;quot;:&amp;quot;21.5&amp;quot;},&amp;quot;1&amp;quot;:&amp;quot;deviceName&amp;quot;:&amp;quot;DHT22&amp;quot;,&amp;quot;valueName&amp;quot;:&amp;quot;humidity&amp;quot;,&amp;quot;type&amp;quot;:2,&amp;quot;value&amp;quot;:&amp;quot;12.2&amp;quot;}}}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Diese &#039;&#039;received content&#039;&#039; Zeile enthält die Daten, die vom ESP via HTTP empfangenen werden. Mehr oder weniger Klartext im JSON Format.&lt;br /&gt;
&lt;br /&gt;
;Basic authentication accepted&lt;br /&gt;
:In diesem Schritt wird geprüft ob eine Authentifizierung erforderlich und im besten Fall auch korrekt ist.&lt;br /&gt;
:Folgende Meldungen wären an dieser Stelle auch möglich:&lt;br /&gt;
:*No basic authentication required (auf beiden Seiten ist keine basic auth eingerichtet)&lt;br /&gt;
:*No basic authentication active but credentials received (auf FHEM Seite ist keine basic auth eingerichtet, der ESP sendet aber basic auth)&lt;br /&gt;
:*Basic authentication rejected (Username oder Passwort passen nicht zusammen)&lt;br /&gt;
&lt;br /&gt;
;Send http close &#039;200 OK&#039;&lt;br /&gt;
:&amp;quot;Quittung&amp;quot; an den ESP senden. Daraufhin wird der ESP die Verbindung beenden.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;Src:&#039;BA_SEN1&#039;/&#039;DHT22&#039; =&amp;gt; ident:BA_SEN1 dev:ESPEasy_BA_SEN1 combinedDevice:1&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Die Daten wurden vom ESP mit dem Namen BA_SEN1 und dem ESP Device DHT22 gesendet. Auf FHEM Seite werden die Daten dem Device mit dem Ident &amp;quot;BA_SEN1&amp;quot; zugewiesen. Dieses Ident wird vom FHEM Device ESPEasy_BA_SEN1 verwendet. Für diesen ESP ist das Attribut &#039;&#039;combineDevices&#039;&#039; wirksam. Wäre &#039;&#039;combineDevices&#039;&#039; nicht aktiv, dann würde das Ident &amp;quot;BA_SEN1_DHT22&amp;quot; lauten.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;dispatch BA_SEN1::10.0.0.148::1::0::1::i||unit||4||0|||i||sleep||0||0|||i||build||137||0|||i||version||9||0|||r||temperature||21.5||2|||r||humidity||12.2||2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Die Daten werden nun von der Bridge an das logische ESPEasy Device weitergegeben.&lt;br /&gt;
:Im Details bedeuten die einzelnen Elemente dieser Zeichenkette:&lt;br /&gt;
:*&#039;&#039;&#039;BA_SEN1::&#039;&#039;&#039;: Daten an das FHEM Device mit dem Ident BA_SEN1 schicken.&lt;br /&gt;
:*&#039;&#039;&#039;10.0.0.148::&#039;&#039;&#039;: IP Adresse des ESPs&lt;br /&gt;
:*&#039;&#039;&#039;1::&#039;&#039;&#039;: autocreate enabled? ja&lt;br /&gt;
:*&#039;&#039;&#039;0::&#039;&#039;&#039;: autosave enabled? nein&lt;br /&gt;
:*&#039;&#039;&#039;1::&#039;&#039;&#039;: wird nicht mehr benutzt&lt;br /&gt;
:*&#039;&#039;&#039;i||unit||4||0|||&#039;&#039;&#039;: Der ESP hat die Unit Nummer 4&lt;br /&gt;
:*&#039;&#039;&#039;i||sleep||1||0|||&#039;&#039;&#039;: Ist der ESP für den deep sleep mode konfiguriert? ja&lt;br /&gt;
:*&#039;&#039;&#039;i||build||137||0|||&#039;&#039;&#039;: ESPEasy build version 137&lt;br /&gt;
:*&#039;&#039;&#039;i||version||9||0|||&#039;&#039;&#039;: ESPEasy Release 9&lt;br /&gt;
:*&#039;&#039;&#039;r||temperature||21.5||2|||&#039;&#039;&#039;: Readingname: temperature, Wert: 21.5, Sensortyp: 2&lt;br /&gt;
:*&#039;&#039;&#039;r||humidity||12.2||2&#039;&#039;&#039;: Readingname: humidity, Wert 12.2, Sensortyp: 2&lt;br /&gt;
:Je nach ESPEasy Firmware Version können die Internals (Zeilen mit i am Anfang) auch &lt;br /&gt;
zusätzliche/andere Informationen aufweisen.&lt;br /&gt;
&lt;br /&gt;
;Closing tcp session.&lt;br /&gt;
:Die tcp Verbindung wird geschlossen, das temporäre ESPEasy Bridge Device wird gelöscht.&lt;br /&gt;
&lt;br /&gt;
===ESPEasy Device===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
2018.02.10 10:08:41.235 5: ESPEasy ESPEasy_BA_SEN1: Received: BA_SEN1::10.0.0.148::1::0::1::i||unit||4||0|||i||sleep||0||0|||i||build||137||0|||i||version||9||0|||r||temperature||21.2||2|||r||humidity||10.3||2&lt;br /&gt;
2018.02.10 10:08:41.236 4: ESPEasy ESPEasy_BA_SEN1: temperature: 21.2&lt;br /&gt;
2018.02.10 10:08:41.237 4: ESPEasy ESPEasy_BA_SEN1: humidity: 10.3&lt;br /&gt;
2018.02.10 10:08:41.237 5: ESPEasy ESPEasy_BA_SEN1: Internals: unit:4 sleep:0 build:137 version:9&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Im Detail:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;Received: BA_SEN1::10.0.0.148::1::0::1::i||unit||4||0|||i||sleep||0||0|||i||build||137||0|||i||version||9||0|||r||temperature||21.2||2|||r||humidity||10.3||2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Das ist wieder die, bereits oben beschriebene, &#039;&#039;dispatch&#039;&#039; Zeichenkette, die jetzt vom logischen Device empfangen wurde.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;ESPEasy ESPEasy_BA_SEN1: temperature: 21.2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;ESPEasy ESPEasy_BA_SEN1: humidity: 10.3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Die Readings &#039;&#039;temperature&#039;&#039; und &#039;&#039;humidity&#039;&#039; wurden aktualisiert.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;ESPEasy ESPEasy_BA_SEN1: Internals: unit:4 sleep:1 build:137 version:9&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
:Die Internals &#039;&#039;unit&#039;&#039;, &#039;&#039;sleep&#039;&#039;, &#039;&#039;build&#039;&#039; und &#039;&#039;version&#039;&#039; wurden aktualisiert.&lt;br /&gt;
&lt;br /&gt;
===Zusätzliche Logeinträge===&lt;br /&gt;
Wird ein Device via Autocreate angelegt, gibt es zusätzliche Einträge im Logfile&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
2018.02.10 10:23:52.243 4: ESPEasy eb_10.0.0.148_3446: Src:&#039;BA_SEN1&#039;/&#039;DHT22&#039; =&amp;gt; ident:BA_SEN1 dev:undef combinedDevice:1&lt;br /&gt;
2018.02.10 10:23:52.243 2: ESPEasy eb: Autocreate ESPEasy_BA_SEN1 ESPEasy 10.0.0.148 80 eb BA_SEN1&lt;br /&gt;
2018.02.10 10:23:52.244 4: ESPEasy ESPEasy_BA_SEN1: Opened for BA_SEN1 10.0.0.148:80 using bridge eb&lt;br /&gt;
2018.02.10 10:23:52.258 5: ESPEasy ESPEasy_BA_SEN1: received event: ATTR ESPEasy_BA_SEN1 setState 3&lt;br /&gt;
2018.02.10 10:23:52.262 5: ESPEasy ESPEasy_BA_SEN1: received event: ATTR ESPEasy_BA_SEN1 Interval 300&lt;br /&gt;
2018.02.10 10:23:52.262 5: ESPEasy ESPEasy_BA_SEN1: Start internalTimer +304 =&amp;gt; 2018-02-10 10:28:57&lt;br /&gt;
2018.02.10 10:23:52.266 5: ESPEasy ESPEasy_BA_SEN1: received event: ATTR ESPEasy_BA_SEN1 presenceCheck 1&lt;br /&gt;
2018.02.10 10:23:52.269 5: ESPEasy ESPEasy_BA_SEN1: received event: ATTR ESPEasy_BA_SEN1 readingSwitchText 1&lt;br /&gt;
2018.02.10 10:23:52.271 2: ESPEasy eb: Autosave is disabled: Do not forget to save changes.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Weblinks==&lt;br /&gt;
*{{Link2CmdRef|Anker=ESPEasy|Lang=en|Label=FHEM ESPEasy Modul-Dokumentation}}&lt;br /&gt;
*[https://www.letscontrolit.com/wiki/index.php/ESPEasy ESP Easy Firmware Wiki] &lt;br /&gt;
*[https://www.letscontrolit.com/wiki/index.php/ESPEasy_Command_Reference ESP Easy Command Reference]&lt;br /&gt;
*[https://www.letscontrolit.com/wiki/index.php/Tutorial_Rules ESP Easy Rules]&lt;br /&gt;
&lt;br /&gt;
==Credits==&lt;br /&gt;
Vielen Dank an:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;ESP Easy Team&#039;&#039;&#039;, für die kontinuierliche Pflege und Erweiterungen der Software&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Drhrin&#039;&#039;&#039;, für die initiale Umsetzung dieses Wiki-Eintags&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=AttrTemplate&amp;diff=31658</id>
		<title>AttrTemplate</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=AttrTemplate&amp;diff=31658"/>
		<updated>2019-11-08T22:56:12Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Eigene templates entwickeln */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:AttrTemplate}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Hilfsmodul bzw. Befehl, das/der die Einrichtung von Geräten erleichtern kann&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=AttrTemplate.pm &lt;br /&gt;
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
AttrTemplate ist ein Hilfsmodul, mit dessen Hilfe Geräte auf einfache Weise mit einer passenden Konfiguration versehen lassen.&lt;br /&gt;
&lt;br /&gt;
Das Modul &#039;&#039;AttrTemplate&#039;&#039; ist indirekt Bestandteil der SetExtensions, das Modul kann von Modulautoren aber auch ohne diese mit in beliebige (Geräte-) Module mit eingebaut werden. Über diesen Mechanismus ist der Befehl &#039;&#039;attrTemplate&#039;&#039; in einer Vielzahl von Modulen verfügbar.&lt;br /&gt;
&lt;br /&gt;
==Einführung==&lt;br /&gt;
Ziel von &#039;&#039;attrTemplate&#039;&#039; ist es, den Nutzer bei der Konfiguration von Geräten zu unterstützen, indem vorrangig entsprechende [[Attribute]] gesetzt werden. Grundsätzlich ist es jedoch auch möglich, beliebige FHEM-Befehle oder Perl-Code im Rahmen von attrTemplate auszulösen. &lt;br /&gt;
Teilt man entsprechende &#039;&#039;templates&#039;&#039;, sollte jedoch deutlich darauf hingewiesen werden, wenn ein Template etwas anderes tut als nur Attribute zu setzen, also insbesondere dauerhafte Konfigurationsänderungen in der Hardware selbst vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
Um Ihnen die Auswahl zu erleichtern, kann &lt;br /&gt;
* mit &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate ?&amp;lt;/code&amp;gt; eine Liste der vorhandenen Templates samt kurzer Beschreibung aufgerufen werden. &lt;br /&gt;
* in der Detailansicht der Geräte über das Dropdownfeld ein &#039;&#039;template&#039;&#039; ausgewählt werden. Nun erhält man unmittelbar unter dem &#039;&#039;set&#039;&#039;-Befehl ebenfalls entsprechende weitere Informationen sowie den Code des &#039;&#039;template&#039;&#039; angezeigt, der bei Drücken auf &#039;&#039;set&#039;&#039; ausgeführt wird.&lt;br /&gt;
Hat man ein passendes &#039;&#039;template&#039;&#039; gefunden, wird mit &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate &amp;lt;template_name&amp;gt;&amp;lt;/code&amp;gt; angewendet, wodurch die entsprechenden, in dem &#039;&#039;template&#039;&#039; hinterlegten Kommandos ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
&lt;br /&gt;
{{Link2Forum|Topic=104804|Message=988100|LinkText=Hier}} hat Rudolf König die Syntax erläutert, die in den attrTemplate-Dateien verwendet werden können:&lt;br /&gt;
* leere Zeilen werden ignoriert&lt;br /&gt;
* Zeilen die mit # anfangen sind Kommentare (s.u. &#039;&#039;desc:&#039;&#039;)&lt;br /&gt;
* Zeilen, die mit einem der folgenden Schlüsselwörter beginnen, werden speziell interpretiert: &#039;&#039;name: filter: prereq: par: desc: farewell: order:&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;name:&#039;&#039;&#039; Name des Templates, markiert gleichzeitig das Ende des vorherigen Templates&lt;br /&gt;
** &#039;&#039;&#039;filter:&#039;&#039;&#039; devspec2array Ausdruck, der beschreibt, für welche Geräte dieses Template anwendbar ist. Wird erst beim &amp;quot;set ?&amp;quot; ausgeführt.&lt;br /&gt;
** &#039;&#039;&#039;prereq:&#039;&#039;&#039; ist entweder ein Perl-Ausdruck {}, oder ein &#039;&#039;devspec2array&#039;&#039;, was genau ein Gerät spezifiziert. Wird beim Einlesen des template Files ausgeführt. Falls nicht wahr ist, werden die darauffolgenden Zeilen des Template nicht ausgeführt. Ist für sowas wie &amp;quot;setze zusätzlich Attribut XY falls die Installation HomeAssistant kennt&amp;quot; gedacht.&lt;br /&gt;
** &#039;&#039;&#039;par:&#039;&#039;&#039; kann mehrfach vorkommen, Syntax: &amp;lt;code&amp;gt;par:&amp;lt;ParamaterName&amp;gt;:&amp;lt;Kommentar&amp;gt;:&amp;lt;Perl-Code&amp;gt;&amp;lt;/code&amp;gt;. &#039;&#039;Perl-Code&#039;&#039; versucht den Wert zu finden, falls nicht möglich (&#039;&#039;return undef&#039;&#039;), wird ein Dialog mit &amp;quot;Replace&amp;quot; angezeigt (bzw. Usage:... im telnet). &#039;&#039;ParameterName&#039;&#039; wird in jeder Befehlzeile ersetzt mit dem Wert. Zusätzlich: &#039;&#039;DEVICE&#039;&#039; wird mit dem Namen des Gerätes ersetzt, wird &#039;&#039;DEVICE&#039;&#039; (z.B. für Modulnamen) als Text benötigt, muß es &#039;&#039;escaped&#039;&#039; werden (z.B. MQTT2_\DEVICE).&lt;br /&gt;
** &#039;&#039;&#039;desc:&#039;&#039;&#039; Kommentar fuer &amp;lt;code&amp;gt;set attrTemplate help ?&amp;lt;/code&amp;gt;. Die letzte Zeile mit # vor &#039;&#039;name:&#039;&#039; wird als &#039;&#039;desc:&#039;&#039; interpretiert, falls kein &#039;&#039;desc:&#039;&#039; vorhanden ist.&lt;br /&gt;
** &#039;&#039;&#039;farewell:&#039;&#039;&#039; wird zum Schluss als Dialog (oder Text in telnet)  angezeigt, falls beim Anwenden der Befehle kein Fehler aufgetreten ist.&lt;br /&gt;
** &#039;&#039;&#039;order:&#039;&#039;&#039; bestimmt die Reihenfolge, in der die Templates im [[FHEMWEB|Webfrontend]] angezeigt werden; falls nicht vorhanden, wird &#039;&#039;name:&#039;&#039; genommen.&lt;br /&gt;
* alle anderen Zeilen werden als auszuführende Befehle interpretiert, wenn man &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate TemplateName&amp;lt;/code&amp;gt; ausführt.&lt;br /&gt;
&lt;br /&gt;
==Eigene Templates entwickeln==&lt;br /&gt;
Wer plant, mehrere gleichartige Geräte anzulegen, aber andere Einstellungen zu wählen, als sie in den vorhandenen Templates enthalten sind, kann hierfür ebenfalls die attrTemplate-Funktion mit eigenen Templates nutzen. Hierfür können die vorhandenen Templates der im Unterverzeichnis &#039;&#039;fhem/FHEM/lib/AttrTemplate&#039;&#039; zu findenden Dateien als Basis dienen. Ihre Templates speichern Sie einfach als neue Datei mit der Endung &#039;&#039;.template&#039;&#039; im selben Verzeichnis und lesen diese mit &amp;lt;code&amp;gt;{ AttrTemplate_Initialize() }&amp;lt;/code&amp;gt; neu ein. Danach können Sie diese direkt verwenden.&lt;br /&gt;
&lt;br /&gt;
Haben Sie ein Template erstellt und möchten dieses teilen, erstellen Sie einfach einen Beitrag im entsprechenden Forenbereichen, für manche Module existieren auch spezielle Threads (siehe Linkliste unten)&lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
* {{Link2Forum|Topic=93370|LinkText=Ankündigung des Moduls im Forum}}&lt;br /&gt;
* [[MQTT2_DEVICE#attrTemplate|Wiki zu attrTemplate und MQTT2_DEVICE]] - enthält auch Links zu speziellen Threads für bestimmte Device-Typen&lt;br /&gt;
* {{Link2Forum|Topic=94495|LinkText=Thread für getestete Vorschläge (MQTT2_DEVICE)}}.&lt;br /&gt;
* {{Link2Forum|Topic=94494|LinkText=Thread für Fragen und Anregungen (MQTT2_DEVICE)}}.&lt;br /&gt;
* {{Link2Forum|Topic=97694|LinkText=Thread für HTTPMOD}}.&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
[[Kategorie:FHEM-Verwendung]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=AttrTemplate&amp;diff=31657</id>
		<title>AttrTemplate</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=AttrTemplate&amp;diff=31657"/>
		<updated>2019-11-08T22:55:58Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Eigene templates entwickeln */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:AttrTemplate}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Hilfsmodul bzw. Befehl, das/der die Einrichtung von Geräten erleichtern kann&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=AttrTemplate.pm &lt;br /&gt;
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
AttrTemplate ist ein Hilfsmodul, mit dessen Hilfe Geräte auf einfache Weise mit einer passenden Konfiguration versehen lassen.&lt;br /&gt;
&lt;br /&gt;
Das Modul &#039;&#039;AttrTemplate&#039;&#039; ist indirekt Bestandteil der SetExtensions, das Modul kann von Modulautoren aber auch ohne diese mit in beliebige (Geräte-) Module mit eingebaut werden. Über diesen Mechanismus ist der Befehl &#039;&#039;attrTemplate&#039;&#039; in einer Vielzahl von Modulen verfügbar.&lt;br /&gt;
&lt;br /&gt;
==Einführung==&lt;br /&gt;
Ziel von &#039;&#039;attrTemplate&#039;&#039; ist es, den Nutzer bei der Konfiguration von Geräten zu unterstützen, indem vorrangig entsprechende [[Attribute]] gesetzt werden. Grundsätzlich ist es jedoch auch möglich, beliebige FHEM-Befehle oder Perl-Code im Rahmen von attrTemplate auszulösen. &lt;br /&gt;
Teilt man entsprechende &#039;&#039;templates&#039;&#039;, sollte jedoch deutlich darauf hingewiesen werden, wenn ein Template etwas anderes tut als nur Attribute zu setzen, also insbesondere dauerhafte Konfigurationsänderungen in der Hardware selbst vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
Um Ihnen die Auswahl zu erleichtern, kann &lt;br /&gt;
* mit &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate ?&amp;lt;/code&amp;gt; eine Liste der vorhandenen Templates samt kurzer Beschreibung aufgerufen werden. &lt;br /&gt;
* in der Detailansicht der Geräte über das Dropdownfeld ein &#039;&#039;template&#039;&#039; ausgewählt werden. Nun erhält man unmittelbar unter dem &#039;&#039;set&#039;&#039;-Befehl ebenfalls entsprechende weitere Informationen sowie den Code des &#039;&#039;template&#039;&#039; angezeigt, der bei Drücken auf &#039;&#039;set&#039;&#039; ausgeführt wird.&lt;br /&gt;
Hat man ein passendes &#039;&#039;template&#039;&#039; gefunden, wird mit &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate &amp;lt;template_name&amp;gt;&amp;lt;/code&amp;gt; angewendet, wodurch die entsprechenden, in dem &#039;&#039;template&#039;&#039; hinterlegten Kommandos ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
&lt;br /&gt;
{{Link2Forum|Topic=104804|Message=988100|LinkText=Hier}} hat Rudolf König die Syntax erläutert, die in den attrTemplate-Dateien verwendet werden können:&lt;br /&gt;
* leere Zeilen werden ignoriert&lt;br /&gt;
* Zeilen die mit # anfangen sind Kommentare (s.u. &#039;&#039;desc:&#039;&#039;)&lt;br /&gt;
* Zeilen, die mit einem der folgenden Schlüsselwörter beginnen, werden speziell interpretiert: &#039;&#039;name: filter: prereq: par: desc: farewell: order:&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;name:&#039;&#039;&#039; Name des Templates, markiert gleichzeitig das Ende des vorherigen Templates&lt;br /&gt;
** &#039;&#039;&#039;filter:&#039;&#039;&#039; devspec2array Ausdruck, der beschreibt, für welche Geräte dieses Template anwendbar ist. Wird erst beim &amp;quot;set ?&amp;quot; ausgeführt.&lt;br /&gt;
** &#039;&#039;&#039;prereq:&#039;&#039;&#039; ist entweder ein Perl-Ausdruck {}, oder ein &#039;&#039;devspec2array&#039;&#039;, was genau ein Gerät spezifiziert. Wird beim Einlesen des template Files ausgeführt. Falls nicht wahr ist, werden die darauffolgenden Zeilen des Template nicht ausgeführt. Ist für sowas wie &amp;quot;setze zusätzlich Attribut XY falls die Installation HomeAssistant kennt&amp;quot; gedacht.&lt;br /&gt;
** &#039;&#039;&#039;par:&#039;&#039;&#039; kann mehrfach vorkommen, Syntax: &amp;lt;code&amp;gt;par:&amp;lt;ParamaterName&amp;gt;:&amp;lt;Kommentar&amp;gt;:&amp;lt;Perl-Code&amp;gt;&amp;lt;/code&amp;gt;. &#039;&#039;Perl-Code&#039;&#039; versucht den Wert zu finden, falls nicht möglich (&#039;&#039;return undef&#039;&#039;), wird ein Dialog mit &amp;quot;Replace&amp;quot; angezeigt (bzw. Usage:... im telnet). &#039;&#039;ParameterName&#039;&#039; wird in jeder Befehlzeile ersetzt mit dem Wert. Zusätzlich: &#039;&#039;DEVICE&#039;&#039; wird mit dem Namen des Gerätes ersetzt, wird &#039;&#039;DEVICE&#039;&#039; (z.B. für Modulnamen) als Text benötigt, muß es &#039;&#039;escaped&#039;&#039; werden (z.B. MQTT2_\DEVICE).&lt;br /&gt;
** &#039;&#039;&#039;desc:&#039;&#039;&#039; Kommentar fuer &amp;lt;code&amp;gt;set attrTemplate help ?&amp;lt;/code&amp;gt;. Die letzte Zeile mit # vor &#039;&#039;name:&#039;&#039; wird als &#039;&#039;desc:&#039;&#039; interpretiert, falls kein &#039;&#039;desc:&#039;&#039; vorhanden ist.&lt;br /&gt;
** &#039;&#039;&#039;farewell:&#039;&#039;&#039; wird zum Schluss als Dialog (oder Text in telnet)  angezeigt, falls beim Anwenden der Befehle kein Fehler aufgetreten ist.&lt;br /&gt;
** &#039;&#039;&#039;order:&#039;&#039;&#039; bestimmt die Reihenfolge, in der die Templates im [[FHEMWEB|Webfrontend]] angezeigt werden; falls nicht vorhanden, wird &#039;&#039;name:&#039;&#039; genommen.&lt;br /&gt;
* alle anderen Zeilen werden als auszuführende Befehle interpretiert, wenn man &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate TemplateName&amp;lt;/code&amp;gt; ausführt.&lt;br /&gt;
&lt;br /&gt;
==Eigene templates entwickeln==&lt;br /&gt;
Wer plant, mehrere gleichartige Geräte anzulegen, aber andere Einstellungen zu wählen, als sie in den vorhandenen Templates enthalten sind, kann hierfür ebenfalls die attrTemplate-Funktion mit eigenen Templates nutzen. Hierfür können die vorhandenen Templates der im Unterverzeichnis &#039;&#039;fhem/FHEM/lib/AttrTemplate&#039;&#039; zu findenden Dateien als Basis dienen. Ihre Templates speichern Sie einfach als neue Datei mit der Endung &#039;&#039;.template&#039;&#039; im selben Verzeichnis und lesen diese mit &amp;lt;code&amp;gt;{ AttrTemplate_Initialize() }&amp;lt;/code&amp;gt; neu ein. Danach können Sie diese direkt verwenden.&lt;br /&gt;
&lt;br /&gt;
Haben Sie ein Template erstellt und möchten dieses teilen, erstellen Sie einfach einen Beitrag im entsprechenden Forenbereichen, für manche Module existieren auch spezielle Threads (siehe Linkliste unten)&lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
* {{Link2Forum|Topic=93370|LinkText=Ankündigung des Moduls im Forum}}&lt;br /&gt;
* [[MQTT2_DEVICE#attrTemplate|Wiki zu attrTemplate und MQTT2_DEVICE]] - enthält auch Links zu speziellen Threads für bestimmte Device-Typen&lt;br /&gt;
* {{Link2Forum|Topic=94495|LinkText=Thread für getestete Vorschläge (MQTT2_DEVICE)}}.&lt;br /&gt;
* {{Link2Forum|Topic=94494|LinkText=Thread für Fragen und Anregungen (MQTT2_DEVICE)}}.&lt;br /&gt;
* {{Link2Forum|Topic=97694|LinkText=Thread für HTTPMOD}}.&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
[[Kategorie:FHEM-Verwendung]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=AttrTemplate&amp;diff=31656</id>
		<title>AttrTemplate</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=AttrTemplate&amp;diff=31656"/>
		<updated>2019-11-08T22:54:42Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Einführung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:AttrTemplate}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Hilfsmodul bzw. Befehl, das/der die Einrichtung von Geräten erleichtern kann&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=AttrTemplate.pm &lt;br /&gt;
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
AttrTemplate ist ein Hilfsmodul, mit dessen Hilfe Geräte auf einfache Weise mit einer passenden Konfiguration versehen lassen.&lt;br /&gt;
&lt;br /&gt;
Das Modul &#039;&#039;AttrTemplate&#039;&#039; ist indirekt Bestandteil der SetExtensions, das Modul kann von Modulautoren aber auch ohne diese mit in beliebige (Geräte-) Module mit eingebaut werden. Über diesen Mechanismus ist der Befehl &#039;&#039;attrTemplate&#039;&#039; in einer Vielzahl von Modulen verfügbar.&lt;br /&gt;
&lt;br /&gt;
==Einführung==&lt;br /&gt;
Ziel von &#039;&#039;attrTemplate&#039;&#039; ist es, den Nutzer bei der Konfiguration von Geräten zu unterstützen, indem vorrangig entsprechende [[Attribute]] gesetzt werden. Grundsätzlich ist es jedoch auch möglich, beliebige FHEM-Befehle oder Perl-Code im Rahmen von attrTemplate auszulösen. &lt;br /&gt;
Teilt man entsprechende &#039;&#039;templates&#039;&#039;, sollte jedoch deutlich darauf hingewiesen werden, wenn ein Template etwas anderes tut als nur Attribute zu setzen, also insbesondere dauerhafte Konfigurationsänderungen in der Hardware selbst vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
Um Ihnen die Auswahl zu erleichtern, kann &lt;br /&gt;
* mit &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate ?&amp;lt;/code&amp;gt; eine Liste der vorhandenen Templates samt kurzer Beschreibung aufgerufen werden. &lt;br /&gt;
* in der Detailansicht der Geräte über das Dropdownfeld ein &#039;&#039;template&#039;&#039; ausgewählt werden. Nun erhält man unmittelbar unter dem &#039;&#039;set&#039;&#039;-Befehl ebenfalls entsprechende weitere Informationen sowie den Code des &#039;&#039;template&#039;&#039; angezeigt, der bei Drücken auf &#039;&#039;set&#039;&#039; ausgeführt wird.&lt;br /&gt;
Hat man ein passendes &#039;&#039;template&#039;&#039; gefunden, wird mit &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate &amp;lt;template_name&amp;gt;&amp;lt;/code&amp;gt; angewendet, wodurch die entsprechenden, in dem &#039;&#039;template&#039;&#039; hinterlegten Kommandos ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
&lt;br /&gt;
{{Link2Forum|Topic=104804|Message=988100|LinkText=Hier}} hat Rudolf König die Syntax erläutert, die in den attrTemplate-Dateien verwendet werden können:&lt;br /&gt;
* leere Zeilen werden ignoriert&lt;br /&gt;
* Zeilen die mit # anfangen sind Kommentare (s.u. &#039;&#039;desc:&#039;&#039;)&lt;br /&gt;
* Zeilen, die mit einem der folgenden Schlüsselwörter beginnen, werden speziell interpretiert: &#039;&#039;name: filter: prereq: par: desc: farewell: order:&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;name:&#039;&#039;&#039; Name des Templates, markiert gleichzeitig das Ende des vorherigen Templates&lt;br /&gt;
** &#039;&#039;&#039;filter:&#039;&#039;&#039; devspec2array Ausdruck, der beschreibt, für welche Geräte dieses Template anwendbar ist. Wird erst beim &amp;quot;set ?&amp;quot; ausgeführt.&lt;br /&gt;
** &#039;&#039;&#039;prereq:&#039;&#039;&#039; ist entweder ein Perl-Ausdruck {}, oder ein &#039;&#039;devspec2array&#039;&#039;, was genau ein Gerät spezifiziert. Wird beim Einlesen des template Files ausgeführt. Falls nicht wahr ist, werden die darauffolgenden Zeilen des Template nicht ausgeführt. Ist für sowas wie &amp;quot;setze zusätzlich Attribut XY falls die Installation HomeAssistant kennt&amp;quot; gedacht.&lt;br /&gt;
** &#039;&#039;&#039;par:&#039;&#039;&#039; kann mehrfach vorkommen, Syntax: &amp;lt;code&amp;gt;par:&amp;lt;ParamaterName&amp;gt;:&amp;lt;Kommentar&amp;gt;:&amp;lt;Perl-Code&amp;gt;&amp;lt;/code&amp;gt;. &#039;&#039;Perl-Code&#039;&#039; versucht den Wert zu finden, falls nicht möglich (&#039;&#039;return undef&#039;&#039;), wird ein Dialog mit &amp;quot;Replace&amp;quot; angezeigt (bzw. Usage:... im telnet). &#039;&#039;ParameterName&#039;&#039; wird in jeder Befehlzeile ersetzt mit dem Wert. Zusätzlich: &#039;&#039;DEVICE&#039;&#039; wird mit dem Namen des Gerätes ersetzt, wird &#039;&#039;DEVICE&#039;&#039; (z.B. für Modulnamen) als Text benötigt, muß es &#039;&#039;escaped&#039;&#039; werden (z.B. MQTT2_\DEVICE).&lt;br /&gt;
** &#039;&#039;&#039;desc:&#039;&#039;&#039; Kommentar fuer &amp;lt;code&amp;gt;set attrTemplate help ?&amp;lt;/code&amp;gt;. Die letzte Zeile mit # vor &#039;&#039;name:&#039;&#039; wird als &#039;&#039;desc:&#039;&#039; interpretiert, falls kein &#039;&#039;desc:&#039;&#039; vorhanden ist.&lt;br /&gt;
** &#039;&#039;&#039;farewell:&#039;&#039;&#039; wird zum Schluss als Dialog (oder Text in telnet)  angezeigt, falls beim Anwenden der Befehle kein Fehler aufgetreten ist.&lt;br /&gt;
** &#039;&#039;&#039;order:&#039;&#039;&#039; bestimmt die Reihenfolge, in der die Templates im [[FHEMWEB|Webfrontend]] angezeigt werden; falls nicht vorhanden, wird &#039;&#039;name:&#039;&#039; genommen.&lt;br /&gt;
* alle anderen Zeilen werden als auszuführende Befehle interpretiert, wenn man &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate TemplateName&amp;lt;/code&amp;gt; ausführt.&lt;br /&gt;
&lt;br /&gt;
==Eigene templates entwickeln==&lt;br /&gt;
Wer plant, mehrere gleichartige Geräte anzulegen, aber andere Einstellungen zu wählen, als sie in den vorhandenen templates enthalten sind, kann hierfür ebenfalls die attrTemplate-Funktion mit eigenen templates nutzen. Hierfür können die vorhandenen templates der im Unterverzeichnis &#039;&#039;fhem/FHEM/lib/AttrTemplate&#039;&#039; zu findenden Dateien als Basis dienen. Ihre Templates speichern Sie einfach als neue Datei mit der Endung &#039;&#039;.template&#039;&#039; im selben Verzeichnis und lesen diese mit &amp;lt;code&amp;gt;{ AttrTemplate_Initialize() }&amp;lt;/code&amp;gt; neu ein. Danach können Sie diese direkt verwenden.&lt;br /&gt;
&lt;br /&gt;
Haben Sie ein Template erstellt und möchten dieses teilen, erstellen Sie einfach einen Beitrag im entsprechenden Forenbereichen, für manche Module existieren auch spezielle Threads (siehe Linkliste unten)&lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
* {{Link2Forum|Topic=93370|LinkText=Ankündigung des Moduls im Forum}}&lt;br /&gt;
* [[MQTT2_DEVICE#attrTemplate|Wiki zu attrTemplate und MQTT2_DEVICE]] - enthält auch Links zu speziellen Threads für bestimmte Device-Typen&lt;br /&gt;
* {{Link2Forum|Topic=94495|LinkText=Thread für getestete Vorschläge (MQTT2_DEVICE)}}.&lt;br /&gt;
* {{Link2Forum|Topic=94494|LinkText=Thread für Fragen und Anregungen (MQTT2_DEVICE)}}.&lt;br /&gt;
* {{Link2Forum|Topic=97694|LinkText=Thread für HTTPMOD}}.&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
[[Kategorie:FHEM-Verwendung]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=AttrTemplate&amp;diff=31655</id>
		<title>AttrTemplate</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=AttrTemplate&amp;diff=31655"/>
		<updated>2019-11-08T22:53:37Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Eigene templates entwickeln */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:AttrTemplate}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Hilfsmodul bzw. Befehl, das/der die Einrichtung von Geräten erleichtern kann&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=AttrTemplate.pm &lt;br /&gt;
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
AttrTemplate ist ein Hilfsmodul, mit dessen Hilfe Geräte auf einfache Weise mit einer passenden Konfiguration versehen lassen.&lt;br /&gt;
&lt;br /&gt;
Das Modul &#039;&#039;AttrTemplate&#039;&#039; ist indirekt Bestandteil der SetExtensions, das Modul kann von Modulautoren aber auch ohne diese mit in beliebige (Geräte-) Module mit eingebaut werden. Über diesen Mechanismus ist der Befehl &#039;&#039;attrTemplate&#039;&#039; in einer Vielzahl von Modulen verfügbar.&lt;br /&gt;
&lt;br /&gt;
==Einführung==&lt;br /&gt;
Ziel von &#039;&#039;attrTemplate&#039;&#039; ist es, den Nutzer bei der Konfiguration von Geräten zu unterstützen, indem vorrangig entsprechende [[Attribute]] gesetzt werden. Grundsätzlich ist es jedoch auch möglich, beliebige FHEM-Befehle oder Perl-Code im Rahmen von attrTemplate auszulösen. &lt;br /&gt;
Teilt man entsprechende &#039;&#039;templates&#039;&#039;, sollte jedoch deutlich darauf hingewiesen werden, wenn ein template etwas anderes tut als nur Attribute zu setzen, also insbesondere dauerhafte Konfigurationsänderungen in der Hardware selbst vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
Um Ihnen die Auswahl zu erleichtern, kann &lt;br /&gt;
* mit &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate ?&amp;lt;/code&amp;gt; eine Liste der vorhandenen Templates samt kurzer Beschreibung aufgerufen werden. &lt;br /&gt;
* in der Detailansicht der Geräte über das Dropdownfeld ein &#039;&#039;template&#039;&#039; ausgewählt werden. Nun erhält man unmittelbar unter dem &#039;&#039;set&#039;&#039;-Befehl ebenfalls entsprechende weitere Informationen sowie den Code des &#039;&#039;template&#039;&#039; angezeigt, der bei Drücken auf &#039;&#039;set&#039;&#039; ausgeführt wird.&lt;br /&gt;
Hat man ein passendes &#039;&#039;template&#039;&#039; gefunden, wird mit &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate &amp;lt;template_name&amp;gt;&amp;lt;/code&amp;gt; angewendet, wodurch die entsprechenden, in dem &#039;&#039;template&#039;&#039; hinterlegten Kommandos ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
&lt;br /&gt;
{{Link2Forum|Topic=104804|Message=988100|LinkText=Hier}} hat Rudolf König die Syntax erläutert, die in den attrTemplate-Dateien verwendet werden können:&lt;br /&gt;
* leere Zeilen werden ignoriert&lt;br /&gt;
* Zeilen die mit # anfangen sind Kommentare (s.u. &#039;&#039;desc:&#039;&#039;)&lt;br /&gt;
* Zeilen, die mit einem der folgenden Schlüsselwörter beginnen, werden speziell interpretiert: &#039;&#039;name: filter: prereq: par: desc: farewell: order:&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;name:&#039;&#039;&#039; Name des Templates, markiert gleichzeitig das Ende des vorherigen Templates&lt;br /&gt;
** &#039;&#039;&#039;filter:&#039;&#039;&#039; devspec2array Ausdruck, der beschreibt, für welche Geräte dieses Template anwendbar ist. Wird erst beim &amp;quot;set ?&amp;quot; ausgeführt.&lt;br /&gt;
** &#039;&#039;&#039;prereq:&#039;&#039;&#039; ist entweder ein Perl-Ausdruck {}, oder ein &#039;&#039;devspec2array&#039;&#039;, was genau ein Gerät spezifiziert. Wird beim Einlesen des template Files ausgeführt. Falls nicht wahr ist, werden die darauffolgenden Zeilen des Template nicht ausgeführt. Ist für sowas wie &amp;quot;setze zusätzlich Attribut XY falls die Installation HomeAssistant kennt&amp;quot; gedacht.&lt;br /&gt;
** &#039;&#039;&#039;par:&#039;&#039;&#039; kann mehrfach vorkommen, Syntax: &amp;lt;code&amp;gt;par:&amp;lt;ParamaterName&amp;gt;:&amp;lt;Kommentar&amp;gt;:&amp;lt;Perl-Code&amp;gt;&amp;lt;/code&amp;gt;. &#039;&#039;Perl-Code&#039;&#039; versucht den Wert zu finden, falls nicht möglich (&#039;&#039;return undef&#039;&#039;), wird ein Dialog mit &amp;quot;Replace&amp;quot; angezeigt (bzw. Usage:... im telnet). &#039;&#039;ParameterName&#039;&#039; wird in jeder Befehlzeile ersetzt mit dem Wert. Zusätzlich: &#039;&#039;DEVICE&#039;&#039; wird mit dem Namen des Gerätes ersetzt, wird &#039;&#039;DEVICE&#039;&#039; (z.B. für Modulnamen) als Text benötigt, muß es &#039;&#039;escaped&#039;&#039; werden (z.B. MQTT2_\DEVICE).&lt;br /&gt;
** &#039;&#039;&#039;desc:&#039;&#039;&#039; Kommentar fuer &amp;lt;code&amp;gt;set attrTemplate help ?&amp;lt;/code&amp;gt;. Die letzte Zeile mit # vor &#039;&#039;name:&#039;&#039; wird als &#039;&#039;desc:&#039;&#039; interpretiert, falls kein &#039;&#039;desc:&#039;&#039; vorhanden ist.&lt;br /&gt;
** &#039;&#039;&#039;farewell:&#039;&#039;&#039; wird zum Schluss als Dialog (oder Text in telnet)  angezeigt, falls beim Anwenden der Befehle kein Fehler aufgetreten ist.&lt;br /&gt;
** &#039;&#039;&#039;order:&#039;&#039;&#039; bestimmt die Reihenfolge, in der die Templates im [[FHEMWEB|Webfrontend]] angezeigt werden; falls nicht vorhanden, wird &#039;&#039;name:&#039;&#039; genommen.&lt;br /&gt;
* alle anderen Zeilen werden als auszuführende Befehle interpretiert, wenn man &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate TemplateName&amp;lt;/code&amp;gt; ausführt.&lt;br /&gt;
&lt;br /&gt;
==Eigene templates entwickeln==&lt;br /&gt;
Wer plant, mehrere gleichartige Geräte anzulegen, aber andere Einstellungen zu wählen, als sie in den vorhandenen templates enthalten sind, kann hierfür ebenfalls die attrTemplate-Funktion mit eigenen templates nutzen. Hierfür können die vorhandenen templates der im Unterverzeichnis &#039;&#039;fhem/FHEM/lib/AttrTemplate&#039;&#039; zu findenden Dateien als Basis dienen. Ihre Templates speichern Sie einfach als neue Datei mit der Endung &#039;&#039;.template&#039;&#039; im selben Verzeichnis und lesen diese mit &amp;lt;code&amp;gt;{ AttrTemplate_Initialize() }&amp;lt;/code&amp;gt; neu ein. Danach können Sie diese direkt verwenden.&lt;br /&gt;
&lt;br /&gt;
Haben Sie ein Template erstellt und möchten dieses teilen, erstellen Sie einfach einen Beitrag im entsprechenden Forenbereichen, für manche Module existieren auch spezielle Threads (siehe Linkliste unten)&lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
* {{Link2Forum|Topic=93370|LinkText=Ankündigung des Moduls im Forum}}&lt;br /&gt;
* [[MQTT2_DEVICE#attrTemplate|Wiki zu attrTemplate und MQTT2_DEVICE]] - enthält auch Links zu speziellen Threads für bestimmte Device-Typen&lt;br /&gt;
* {{Link2Forum|Topic=94495|LinkText=Thread für getestete Vorschläge (MQTT2_DEVICE)}}.&lt;br /&gt;
* {{Link2Forum|Topic=94494|LinkText=Thread für Fragen und Anregungen (MQTT2_DEVICE)}}.&lt;br /&gt;
* {{Link2Forum|Topic=97694|LinkText=Thread für HTTPMOD}}.&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
[[Kategorie:FHEM-Verwendung]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=AttrTemplate&amp;diff=31654</id>
		<title>AttrTemplate</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=AttrTemplate&amp;diff=31654"/>
		<updated>2019-11-08T22:52:13Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Syntax */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:AttrTemplate}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Hilfsmodul bzw. Befehl, das/der die Einrichtung von Geräten erleichtern kann&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=AttrTemplate.pm &lt;br /&gt;
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
AttrTemplate ist ein Hilfsmodul, mit dessen Hilfe Geräte auf einfache Weise mit einer passenden Konfiguration versehen lassen.&lt;br /&gt;
&lt;br /&gt;
Das Modul &#039;&#039;AttrTemplate&#039;&#039; ist indirekt Bestandteil der SetExtensions, das Modul kann von Modulautoren aber auch ohne diese mit in beliebige (Geräte-) Module mit eingebaut werden. Über diesen Mechanismus ist der Befehl &#039;&#039;attrTemplate&#039;&#039; in einer Vielzahl von Modulen verfügbar.&lt;br /&gt;
&lt;br /&gt;
==Einführung==&lt;br /&gt;
Ziel von &#039;&#039;attrTemplate&#039;&#039; ist es, den Nutzer bei der Konfiguration von Geräten zu unterstützen, indem vorrangig entsprechende [[Attribute]] gesetzt werden. Grundsätzlich ist es jedoch auch möglich, beliebige FHEM-Befehle oder Perl-Code im Rahmen von attrTemplate auszulösen. &lt;br /&gt;
Teilt man entsprechende &#039;&#039;templates&#039;&#039;, sollte jedoch deutlich darauf hingewiesen werden, wenn ein template etwas anderes tut als nur Attribute zu setzen, also insbesondere dauerhafte Konfigurationsänderungen in der Hardware selbst vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
Um Ihnen die Auswahl zu erleichtern, kann &lt;br /&gt;
* mit &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate ?&amp;lt;/code&amp;gt; eine Liste der vorhandenen Templates samt kurzer Beschreibung aufgerufen werden. &lt;br /&gt;
* in der Detailansicht der Geräte über das Dropdownfeld ein &#039;&#039;template&#039;&#039; ausgewählt werden. Nun erhält man unmittelbar unter dem &#039;&#039;set&#039;&#039;-Befehl ebenfalls entsprechende weitere Informationen sowie den Code des &#039;&#039;template&#039;&#039; angezeigt, der bei Drücken auf &#039;&#039;set&#039;&#039; ausgeführt wird.&lt;br /&gt;
Hat man ein passendes &#039;&#039;template&#039;&#039; gefunden, wird mit &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate &amp;lt;template_name&amp;gt;&amp;lt;/code&amp;gt; angewendet, wodurch die entsprechenden, in dem &#039;&#039;template&#039;&#039; hinterlegten Kommandos ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
&lt;br /&gt;
{{Link2Forum|Topic=104804|Message=988100|LinkText=Hier}} hat Rudolf König die Syntax erläutert, die in den attrTemplate-Dateien verwendet werden können:&lt;br /&gt;
* leere Zeilen werden ignoriert&lt;br /&gt;
* Zeilen die mit # anfangen sind Kommentare (s.u. &#039;&#039;desc:&#039;&#039;)&lt;br /&gt;
* Zeilen, die mit einem der folgenden Schlüsselwörter beginnen, werden speziell interpretiert: &#039;&#039;name: filter: prereq: par: desc: farewell: order:&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;name:&#039;&#039;&#039; Name des Templates, markiert gleichzeitig das Ende des vorherigen Templates&lt;br /&gt;
** &#039;&#039;&#039;filter:&#039;&#039;&#039; devspec2array Ausdruck, der beschreibt, für welche Geräte dieses Template anwendbar ist. Wird erst beim &amp;quot;set ?&amp;quot; ausgeführt.&lt;br /&gt;
** &#039;&#039;&#039;prereq:&#039;&#039;&#039; ist entweder ein Perl-Ausdruck {}, oder ein &#039;&#039;devspec2array&#039;&#039;, was genau ein Gerät spezifiziert. Wird beim Einlesen des template Files ausgeführt. Falls nicht wahr ist, werden die darauffolgenden Zeilen des Template nicht ausgeführt. Ist für sowas wie &amp;quot;setze zusätzlich Attribut XY falls die Installation HomeAssistant kennt&amp;quot; gedacht.&lt;br /&gt;
** &#039;&#039;&#039;par:&#039;&#039;&#039; kann mehrfach vorkommen, Syntax: &amp;lt;code&amp;gt;par:&amp;lt;ParamaterName&amp;gt;:&amp;lt;Kommentar&amp;gt;:&amp;lt;Perl-Code&amp;gt;&amp;lt;/code&amp;gt;. &#039;&#039;Perl-Code&#039;&#039; versucht den Wert zu finden, falls nicht möglich (&#039;&#039;return undef&#039;&#039;), wird ein Dialog mit &amp;quot;Replace&amp;quot; angezeigt (bzw. Usage:... im telnet). &#039;&#039;ParameterName&#039;&#039; wird in jeder Befehlzeile ersetzt mit dem Wert. Zusätzlich: &#039;&#039;DEVICE&#039;&#039; wird mit dem Namen des Gerätes ersetzt, wird &#039;&#039;DEVICE&#039;&#039; (z.B. für Modulnamen) als Text benötigt, muß es &#039;&#039;escaped&#039;&#039; werden (z.B. MQTT2_\DEVICE).&lt;br /&gt;
** &#039;&#039;&#039;desc:&#039;&#039;&#039; Kommentar fuer &amp;lt;code&amp;gt;set attrTemplate help ?&amp;lt;/code&amp;gt;. Die letzte Zeile mit # vor &#039;&#039;name:&#039;&#039; wird als &#039;&#039;desc:&#039;&#039; interpretiert, falls kein &#039;&#039;desc:&#039;&#039; vorhanden ist.&lt;br /&gt;
** &#039;&#039;&#039;farewell:&#039;&#039;&#039; wird zum Schluss als Dialog (oder Text in telnet)  angezeigt, falls beim Anwenden der Befehle kein Fehler aufgetreten ist.&lt;br /&gt;
** &#039;&#039;&#039;order:&#039;&#039;&#039; bestimmt die Reihenfolge, in der die Templates im [[FHEMWEB|Webfrontend]] angezeigt werden; falls nicht vorhanden, wird &#039;&#039;name:&#039;&#039; genommen.&lt;br /&gt;
* alle anderen Zeilen werden als auszuführende Befehle interpretiert, wenn man &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate TemplateName&amp;lt;/code&amp;gt; ausführt.&lt;br /&gt;
&lt;br /&gt;
==Eigene templates entwickeln==&lt;br /&gt;
Wer plant, mehrere gleichartige Geräte anzulegen, aber andere Einstellungen zu wählen, als sie in den vorhandenen templates enthalten sind, kann hierfür ebenfalls die attrTemplate-Funktion mit eigenen templates nutzen. Hierfür können die vorhandenen templates der im Unterverzeichnis &#039;&#039;fhem/FHEM/lib/AttrTemplate&#039;&#039; zu findenden Dateien als Basis dienen, Ihre templates speichern Sie einfach als neue Datei mit der Endung &#039;&#039;.template&#039;&#039; im selben Verzeichnis und lesen diese mit &amp;lt;code&amp;gt;{ AttrTemplate_Initialize() }&amp;lt;/code&amp;gt; neu ein. Danach können Sie diese direkt verwenden.&lt;br /&gt;
&lt;br /&gt;
Haben Sie ein template erstellt und möchten dieses teilen, erstellen Sie einfach einen Beitrag im entsprechenden Forenbereichen, für manche Module existieren auch spezielle Threads (siehe Linkliste unten) &lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
* {{Link2Forum|Topic=93370|LinkText=Ankündigung des Moduls im Forum}}&lt;br /&gt;
* [[MQTT2_DEVICE#attrTemplate|Wiki zu attrTemplate und MQTT2_DEVICE]] - enthält auch Links zu speziellen Threads für bestimmte Device-Typen&lt;br /&gt;
* {{Link2Forum|Topic=94495|LinkText=Thread für getestete Vorschläge (MQTT2_DEVICE)}}.&lt;br /&gt;
* {{Link2Forum|Topic=94494|LinkText=Thread für Fragen und Anregungen (MQTT2_DEVICE)}}.&lt;br /&gt;
* {{Link2Forum|Topic=97694|LinkText=Thread für HTTPMOD}}.&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
[[Kategorie:FHEM-Verwendung]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=AttrTemplate&amp;diff=31653</id>
		<title>AttrTemplate</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=AttrTemplate&amp;diff=31653"/>
		<updated>2019-11-08T22:51:35Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Einführung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:AttrTemplate}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Hilfsmodul bzw. Befehl, das/der die Einrichtung von Geräten erleichtern kann&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=AttrTemplate.pm &lt;br /&gt;
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
AttrTemplate ist ein Hilfsmodul, mit dessen Hilfe Geräte auf einfache Weise mit einer passenden Konfiguration versehen lassen.&lt;br /&gt;
&lt;br /&gt;
Das Modul &#039;&#039;AttrTemplate&#039;&#039; ist indirekt Bestandteil der SetExtensions, das Modul kann von Modulautoren aber auch ohne diese mit in beliebige (Geräte-) Module mit eingebaut werden. Über diesen Mechanismus ist der Befehl &#039;&#039;attrTemplate&#039;&#039; in einer Vielzahl von Modulen verfügbar.&lt;br /&gt;
&lt;br /&gt;
==Einführung==&lt;br /&gt;
Ziel von &#039;&#039;attrTemplate&#039;&#039; ist es, den Nutzer bei der Konfiguration von Geräten zu unterstützen, indem vorrangig entsprechende [[Attribute]] gesetzt werden. Grundsätzlich ist es jedoch auch möglich, beliebige FHEM-Befehle oder Perl-Code im Rahmen von attrTemplate auszulösen. &lt;br /&gt;
Teilt man entsprechende &#039;&#039;templates&#039;&#039;, sollte jedoch deutlich darauf hingewiesen werden, wenn ein template etwas anderes tut als nur Attribute zu setzen, also insbesondere dauerhafte Konfigurationsänderungen in der Hardware selbst vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
Um Ihnen die Auswahl zu erleichtern, kann &lt;br /&gt;
* mit &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate ?&amp;lt;/code&amp;gt; eine Liste der vorhandenen Templates samt kurzer Beschreibung aufgerufen werden. &lt;br /&gt;
* in der Detailansicht der Geräte über das Dropdownfeld ein &#039;&#039;template&#039;&#039; ausgewählt werden. Nun erhält man unmittelbar unter dem &#039;&#039;set&#039;&#039;-Befehl ebenfalls entsprechende weitere Informationen sowie den Code des &#039;&#039;template&#039;&#039; angezeigt, der bei Drücken auf &#039;&#039;set&#039;&#039; ausgeführt wird.&lt;br /&gt;
Hat man ein passendes &#039;&#039;template&#039;&#039; gefunden, wird mit &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate &amp;lt;template_name&amp;gt;&amp;lt;/code&amp;gt; angewendet, wodurch die entsprechenden, in dem &#039;&#039;template&#039;&#039; hinterlegten Kommandos ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
&lt;br /&gt;
{{Link2Forum|Topic=104804|Message=988100|LinkText=Hier}} hat Rudolf König die Syntax erläutert, die in den attrTemplate-Dateien verwendet werden kann:&lt;br /&gt;
* leere Zeilen werden ignoriert&lt;br /&gt;
* Zeilen die mit # anfangen sind Kommentare (s.u. &#039;&#039;desc:&#039;&#039;)&lt;br /&gt;
* Zeilen, die mit einem der folgenden Schlüsselwörter beginnen, werden speziell interpretiert: &#039;&#039;name: filter: prereq: par: desc: farewell: order:&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;name:&#039;&#039;&#039; Name des Templates, markiert gleichzeitig das Ende des vorherigen Templates&lt;br /&gt;
** &#039;&#039;&#039;filter:&#039;&#039;&#039; devspec2array Ausdruck, der beschreibt, für welche Geräte dieses Template anwendbar ist. Wird erst beim &amp;quot;set ?&amp;quot; ausgeführt.&lt;br /&gt;
** &#039;&#039;&#039;prereq:&#039;&#039;&#039; ist entweder ein Perl-Ausdruck {}, oder ein &#039;&#039;devspec2array&#039;&#039;, was genau ein Gerät spezifiziert. Wird beim Einlesen des template Files ausgeführt. Falls nicht wahr ist, werden die darauffolgenden Zeilen des Template nicht ausgeführt. Ist für sowas wie &amp;quot;setze zusätzlich Attribut XY falls die Installation HomeAssistant kennt&amp;quot; gedacht.&lt;br /&gt;
** &#039;&#039;&#039;par:&#039;&#039;&#039; kann mehrfach vorkommen, Syntax: &amp;lt;code&amp;gt;par:&amp;lt;ParamaterName&amp;gt;:&amp;lt;Kommentar&amp;gt;:&amp;lt;Perl-Code&amp;gt;&amp;lt;/code&amp;gt;. &#039;&#039;Perl-Code&#039;&#039; versucht den Wert zu finden, falls nicht möglich (&#039;&#039;return undef&#039;&#039;), wird ein Dialog mit &amp;quot;Replace&amp;quot; angezeigt (bzw. Usage:... im telnet). &#039;&#039;ParameterName&#039;&#039; wird in jeder Befehlzeile ersetzt mit dem Wert. Zusätzlich: &#039;&#039;DEVICE&#039;&#039; wird mit dem Namen des Gerätes ersetzt, wird &#039;&#039;DEVICE&#039;&#039; (z.B. für Modulnamen) als Text benötigt, muß es &#039;&#039;escaped&#039;&#039; werden (z.B. MQTT2_\DEVICE).&lt;br /&gt;
** &#039;&#039;&#039;desc:&#039;&#039;&#039; Kommentar fuer &amp;lt;code&amp;gt;set attrTemplate help ?&amp;lt;/code&amp;gt;. Die letzte Zeile mit # vor &#039;&#039;name:&#039;&#039; wird als &#039;&#039;desc:&#039;&#039; interpretiert, falls kein &#039;&#039;desc:&#039;&#039; vorhanden ist.&lt;br /&gt;
** &#039;&#039;&#039;farewell:&#039;&#039;&#039; wird zum Schluss als Dialog (oder Text in telnet)  angezeigt, falls beim Anwenden der Befehle kein Fehler aufgetreten ist.&lt;br /&gt;
** &#039;&#039;&#039;order:&#039;&#039;&#039; bestimmt die Reihenfolge, in der die Templates im [[FHEMWEB|Webfrontend]] angezeigt werden; falls nicht vorhanden, wird &#039;&#039;name:&#039;&#039; genommen.&lt;br /&gt;
* alle anderen Zeilen werden als auszuführende Befehle interpretiert, wenn man &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate TemplateName&amp;lt;/code&amp;gt; ausführt.&lt;br /&gt;
&lt;br /&gt;
==Eigene templates entwickeln==&lt;br /&gt;
Wer plant, mehrere gleichartige Geräte anzulegen, aber andere Einstellungen zu wählen, als sie in den vorhandenen templates enthalten sind, kann hierfür ebenfalls die attrTemplate-Funktion mit eigenen templates nutzen. Hierfür können die vorhandenen templates der im Unterverzeichnis &#039;&#039;fhem/FHEM/lib/AttrTemplate&#039;&#039; zu findenden Dateien als Basis dienen, Ihre templates speichern Sie einfach als neue Datei mit der Endung &#039;&#039;.template&#039;&#039; im selben Verzeichnis und lesen diese mit &amp;lt;code&amp;gt;{ AttrTemplate_Initialize() }&amp;lt;/code&amp;gt; neu ein. Danach können Sie diese direkt verwenden.&lt;br /&gt;
&lt;br /&gt;
Haben Sie ein template erstellt und möchten dieses teilen, erstellen Sie einfach einen Beitrag im entsprechenden Forenbereichen, für manche Module existieren auch spezielle Threads (siehe Linkliste unten) &lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
* {{Link2Forum|Topic=93370|LinkText=Ankündigung des Moduls im Forum}}&lt;br /&gt;
* [[MQTT2_DEVICE#attrTemplate|Wiki zu attrTemplate und MQTT2_DEVICE]] - enthält auch Links zu speziellen Threads für bestimmte Device-Typen&lt;br /&gt;
* {{Link2Forum|Topic=94495|LinkText=Thread für getestete Vorschläge (MQTT2_DEVICE)}}.&lt;br /&gt;
* {{Link2Forum|Topic=94494|LinkText=Thread für Fragen und Anregungen (MQTT2_DEVICE)}}.&lt;br /&gt;
* {{Link2Forum|Topic=97694|LinkText=Thread für HTTPMOD}}.&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
[[Kategorie:FHEM-Verwendung]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=AttrTemplate&amp;diff=31652</id>
		<title>AttrTemplate</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=AttrTemplate&amp;diff=31652"/>
		<updated>2019-11-08T22:49:00Z</updated>

		<summary type="html">&lt;p&gt;Maista: Tippfehler&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SEITENTITEL:AttrTemplate}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=Hilfsmodul bzw. Befehl, das/der die Einrichtung von Geräten erleichtern kann&lt;br /&gt;
|ModType=cmd&lt;br /&gt;
|ModCmdRef=&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=AttrTemplate.pm &lt;br /&gt;
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
AttrTemplate ist ein Hilfsmodul, mit dessen Hilfe Geräte auf einfache Weise mit einer passenden Konfiguration versehen lassen.&lt;br /&gt;
&lt;br /&gt;
Das Modul &#039;&#039;AttrTemplate&#039;&#039; ist indirekt Bestandteil der SetExtensions, das Modul kann von Modulautoren aber auch ohne diese mit in beliebige (Geräte-) Module mit eingebaut werden. Über diesen Mechanismus ist der Befehl &#039;&#039;attrTemplate&#039;&#039; in einer Vielzahl von Modulen verfügbar.&lt;br /&gt;
&lt;br /&gt;
==Einführung==&lt;br /&gt;
Ziel von &#039;&#039;attrTemplate&#039;&#039; ist es, den Nutzer bei der Konfiguration von Geräten zu unterstützen, indem vorrangig entsprechende [[Attribute]] gesetzt werden. Grundsätzlich ist es jedoch auch möglich, beliebige FHEM-Befehle oder Perl-Code im Rahmen von attrTemplate auszulösen. &lt;br /&gt;
Teilt man entsprechende &#039;&#039;templates&#039;&#039;, sollte jedoch deutlich darauf hingewiesen werden, wenn ein template etwas anderes tut als nur Attribute zu setzen, also insbesondere dauerhafte Konfigurationsänderungen in der Hardware selbst vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
Um Ihnen die Auswahl zu erleichtern, kann &lt;br /&gt;
* mit &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate ?&amp;lt;/code&amp;gt; eine Liste der vorhandenen Templates samt kurzer Beschreibung aufgerufen werden. &lt;br /&gt;
* in der Detailansicht der Geräte über das Dropdownfeld ein &#039;&#039;template&#039;&#039; ausgewählt werden; dann erhält man unmittelbar unter dem &#039;&#039;set&#039;&#039;-Befehl ebenfalls entsprechende weitere Informationen sowie den Code des &#039;&#039;template&#039;&#039; angezeigt, der bei Drücken auf &#039;&#039;set&#039;&#039; ausgeführt wird.&lt;br /&gt;
Hat man ein passendes &#039;&#039;template&#039;&#039; gefunden, wird mit &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate &amp;lt;template_name&amp;gt;&amp;lt;/code&amp;gt; angewendet, wodurch die entsprechenden, in dem &#039;&#039;template&#039;&#039; hinterlegten Kommandos ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
&lt;br /&gt;
{{Link2Forum|Topic=104804|Message=988100|LinkText=Hier}} hat Rudolf König die Syntax erläutert, die in den attrTemplate-Dateien verwendet werden kann:&lt;br /&gt;
* leere Zeilen werden ignoriert&lt;br /&gt;
* Zeilen die mit # anfangen sind Kommentare (s.u. &#039;&#039;desc:&#039;&#039;)&lt;br /&gt;
* Zeilen, die mit einem der folgenden Schlüsselwörter beginnen, werden speziell interpretiert: &#039;&#039;name: filter: prereq: par: desc: farewell: order:&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;name:&#039;&#039;&#039; Name des Templates, markiert gleichzeitig das Ende des vorherigen Templates&lt;br /&gt;
** &#039;&#039;&#039;filter:&#039;&#039;&#039; devspec2array Ausdruck, der beschreibt, für welche Geräte dieses Template anwendbar ist. Wird erst beim &amp;quot;set ?&amp;quot; ausgeführt.&lt;br /&gt;
** &#039;&#039;&#039;prereq:&#039;&#039;&#039; ist entweder ein Perl-Ausdruck {}, oder ein &#039;&#039;devspec2array&#039;&#039;, was genau ein Gerät spezifiziert. Wird beim Einlesen des template Files ausgeführt. Falls nicht wahr ist, werden die darauffolgenden Zeilen des Template nicht ausgeführt. Ist für sowas wie &amp;quot;setze zusätzlich Attribut XY falls die Installation HomeAssistant kennt&amp;quot; gedacht.&lt;br /&gt;
** &#039;&#039;&#039;par:&#039;&#039;&#039; kann mehrfach vorkommen, Syntax: &amp;lt;code&amp;gt;par:&amp;lt;ParamaterName&amp;gt;:&amp;lt;Kommentar&amp;gt;:&amp;lt;Perl-Code&amp;gt;&amp;lt;/code&amp;gt;. &#039;&#039;Perl-Code&#039;&#039; versucht den Wert zu finden, falls nicht möglich (&#039;&#039;return undef&#039;&#039;), wird ein Dialog mit &amp;quot;Replace&amp;quot; angezeigt (bzw. Usage:... im telnet). &#039;&#039;ParameterName&#039;&#039; wird in jeder Befehlzeile ersetzt mit dem Wert. Zusätzlich: &#039;&#039;DEVICE&#039;&#039; wird mit dem Namen des Gerätes ersetzt, wird &#039;&#039;DEVICE&#039;&#039; (z.B. für Modulnamen) als Text benötigt, muß es &#039;&#039;escaped&#039;&#039; werden (z.B. MQTT2_\DEVICE).&lt;br /&gt;
** &#039;&#039;&#039;desc:&#039;&#039;&#039; Kommentar fuer &amp;lt;code&amp;gt;set attrTemplate help ?&amp;lt;/code&amp;gt;. Die letzte Zeile mit # vor &#039;&#039;name:&#039;&#039; wird als &#039;&#039;desc:&#039;&#039; interpretiert, falls kein &#039;&#039;desc:&#039;&#039; vorhanden ist.&lt;br /&gt;
** &#039;&#039;&#039;farewell:&#039;&#039;&#039; wird zum Schluss als Dialog (oder Text in telnet)  angezeigt, falls beim Anwenden der Befehle kein Fehler aufgetreten ist.&lt;br /&gt;
** &#039;&#039;&#039;order:&#039;&#039;&#039; bestimmt die Reihenfolge, in der die Templates im [[FHEMWEB|Webfrontend]] angezeigt werden; falls nicht vorhanden, wird &#039;&#039;name:&#039;&#039; genommen.&lt;br /&gt;
* alle anderen Zeilen werden als auszuführende Befehle interpretiert, wenn man &amp;lt;code&amp;gt;set &amp;lt;Device-Name&amp;gt; attrTemplate TemplateName&amp;lt;/code&amp;gt; ausführt.&lt;br /&gt;
&lt;br /&gt;
==Eigene templates entwickeln==&lt;br /&gt;
Wer plant, mehrere gleichartige Geräte anzulegen, aber andere Einstellungen zu wählen, als sie in den vorhandenen templates enthalten sind, kann hierfür ebenfalls die attrTemplate-Funktion mit eigenen templates nutzen. Hierfür können die vorhandenen templates der im Unterverzeichnis &#039;&#039;fhem/FHEM/lib/AttrTemplate&#039;&#039; zu findenden Dateien als Basis dienen, Ihre templates speichern Sie einfach als neue Datei mit der Endung &#039;&#039;.template&#039;&#039; im selben Verzeichnis und lesen diese mit &amp;lt;code&amp;gt;{ AttrTemplate_Initialize() }&amp;lt;/code&amp;gt; neu ein. Danach können Sie diese direkt verwenden.&lt;br /&gt;
&lt;br /&gt;
Haben Sie ein template erstellt und möchten dieses teilen, erstellen Sie einfach einen Beitrag im entsprechenden Forenbereichen, für manche Module existieren auch spezielle Threads (siehe Linkliste unten) &lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
* {{Link2Forum|Topic=93370|LinkText=Ankündigung des Moduls im Forum}}&lt;br /&gt;
* [[MQTT2_DEVICE#attrTemplate|Wiki zu attrTemplate und MQTT2_DEVICE]] - enthält auch Links zu speziellen Threads für bestimmte Device-Typen&lt;br /&gt;
* {{Link2Forum|Topic=94495|LinkText=Thread für getestete Vorschläge (MQTT2_DEVICE)}}.&lt;br /&gt;
* {{Link2Forum|Topic=94494|LinkText=Thread für Fragen und Anregungen (MQTT2_DEVICE)}}.&lt;br /&gt;
* {{Link2Forum|Topic=97694|LinkText=Thread für HTTPMOD}}.&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
[[Kategorie:FHEM-Verwendung]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Blinken_-_Impulsgenerator_mit_variablem_Tastgrad&amp;diff=31651</id>
		<title>Blinken - Impulsgenerator mit variablem Tastgrad</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Blinken_-_Impulsgenerator_mit_variablem_Tastgrad&amp;diff=31651"/>
		<updated>2019-11-08T22:44:28Z</updated>

		<summary type="html">&lt;p&gt;Maista: Code in &amp;lt;pre&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Blinken - Impulsgenerator mit variablem Tastgrad =&lt;br /&gt;
== Import ==&lt;br /&gt;
Die folgende Definition kann als Testraum in die eigene FHEM-Installation ohne Seiteneffekte importiert werden, indem man auf das Pluszeichen oben links im Webinterface klickt. Falls dieses unsichtbar sein sollte, kann es z.B über den Style f18 sichtbar gemacht werden.&lt;br /&gt;
[[Datei:Import nach FHEM1.png|mini|Import nach FHEM Schritt 1]]&lt;br /&gt;
[[Datei:Importfenster.png|mini|Import nach FHEM Schritt 2]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod Pulse MSwitch     # MSwitch_Self pulsedevice&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse MSwitch_Debug 0&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse MSwitch_Delete_Delays 1&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse MSwitch_Eventhistory 0&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse MSwitch_Expert 1&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse MSwitch_Extensions 1&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse MSwitch_Help 1&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse MSwitch_Ignore_Types &amp;quot;TYPE=MSwitch&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse MSwitch_Include_Devicecmds 1&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse MSwitch_Include_MSwitchcmds 0&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse MSwitch_Include_Webcmds 0&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse MSwitch_Inforoom MSwitch&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse MSwitch_Lock_Quickedit 1&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse MSwitch_Mode Full&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse MSwitch_Safemode 1&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse readingList onpulse offpulse&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse room 07_Pulse&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse setList onpulse:00:00:01,00:00:02,00:00:03,00:00:04,00:00:05 offpulse:00:00:01,00:00:02,00:00:03,00:00:04,00:00:05&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse webCmd on:off:onpulse:offpulse&amp;lt;br&amp;gt;&lt;br /&gt;
attr Pulse webCmdLabel ::ontime:offtime&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod pulsedevice MSwitch  # no_device&amp;lt;br&amp;gt;&lt;br /&gt;
attr pulsedevice MSwitch_Debug 0&amp;lt;br&amp;gt;&lt;br /&gt;
attr pulsedevice MSwitch_Eventhistory 0&amp;lt;br&amp;gt;&lt;br /&gt;
attr pulsedevice MSwitch_Help 0&amp;lt;br&amp;gt;&lt;br /&gt;
attr pulsedevice MSwitch_Ignore_Types notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&amp;lt;br&amp;gt;&lt;br /&gt;
attr pulsedevice MSwitch_Inforoom MSwitch&amp;lt;br&amp;gt;&lt;br /&gt;
attr pulsedevice MSwitch_Mode Dummy&amp;lt;br&amp;gt;&lt;br /&gt;
attr pulsedevice room 07_Pulse&amp;lt;br&amp;gt;&lt;br /&gt;
attr pulsedevice setList on off&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;setstate Pulse off&amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 14:17:18 .Device_Affected MSwitch_Self-AbsCmd1,MSwitch_Self-AbsCmd2,pulsedevice-AbsCmd1,pulsedevice-AbsCmd2&amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 14:21:52 .Device_Affected_Details MSwitch_Self-AbsCmd1#[NF]exec_cmd_1#[NF]no_action#[NF]ID#[sp]1#[NF]#[NF]delay1#[NF]delay1#[NF][Pulse#[dp]onpulse]#[NF]00#[dp]00#[dp]00#[NF]#[NF]#[NF]0#[NF]0#[NF]1#[NF]0#[NF]#[NF]0#[NF]0#[NF]3#[ND]MSwitch_Self-AbsCmd2#[NF]exec_cmd_1#[NF]no_action#[NF]#[NF]#[NF]delay1#[NF]delay1#[NF][Pulse#[dp]offpulse]#[NF]00#[dp]00#[dp]00#[NF]#[NF]#[NF]0#[NF]0#[NF]1#[NF]1#[NF]#[NF]0#[NF]0#[NF]4#[ND]pulsedevice-AbsCmd1#[NF]on#[NF]off#[NF]#[NF]#[NF]delay1#[NF]delay1#[NF]00#[dp]00#[dp]00#[NF]00#[dp]00#[dp]00#[NF]#[NF]#[NF]0#[NF]0#[NF]1#[NF]0#[NF]#[NF]0#[NF]0#[NF]1#[ND]pulsedevice-AbsCmd2#[NF]off#[NF]no_action#[NF]#[NF]#[NF]delay2#[NF]delay1#[NF][Pulse#[dp]onpulse]#[NF]00#[dp]00#[dp]00#[NF]#[NF]#[NF]0#[NF]0#[NF]1#[NF]0#[NF]#[NF]0#[NF]0#[NF]2&amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 12:31:25 .Device_Events no_trigger&amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 12:31:25 .First_init done&amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 12:31:25 .Trigger_cmd_off no_trigger&amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 12:31:25 .Trigger_cmd_on no_trigger&amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 12:31:25 .Trigger_off no_trigger&amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 12:31:25 .Trigger_on no_trigger&amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 12:31:25 .V_Check V2.00&amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 14:18:43 .sortby show&amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 12:31:25 Trigger_log off&amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 14:21:24 last_activation_by manual&amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 14:21:23 last_cmd 1&amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 14:21:23 last_exec_cmd set Pulse exec_cmd_1 &amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 14:21:05 offpulse 00:00:05&amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 14:19:18 onpulse 00:00:02&amp;lt;br&amp;gt;&lt;br /&gt;
setstate Pulse 2019-11-03 14:21:24 state off&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;setstate pulsedevice on&amp;lt;br&amp;gt;&lt;br /&gt;
setstate pulsedevice 2019-11-03 12:32:30 .Device_Affected no_device&amp;lt;br&amp;gt;&lt;br /&gt;
setstate pulsedevice 2019-11-03 12:32:30 .Device_Events no_trigger&amp;lt;br&amp;gt;&lt;br /&gt;
setstate pulsedevice 2019-11-03 12:32:30 .First_init done&amp;lt;br&amp;gt;&lt;br /&gt;
setstate pulsedevice 2019-11-03 12:32:30 .Trigger_cmd_off no_trigger&amp;lt;br&amp;gt;&lt;br /&gt;
setstate pulsedevice 2019-11-03 12:32:30 .Trigger_cmd_on no_trigger&amp;lt;br&amp;gt;&lt;br /&gt;
setstate pulsedevice 2019-11-03 12:32:30 .Trigger_off no_trigger&amp;lt;br&amp;gt;&lt;br /&gt;
setstate pulsedevice 2019-11-03 12:32:30 .Trigger_on no_trigger&amp;lt;br&amp;gt;&lt;br /&gt;
setstate pulsedevice 2019-11-03 12:32:30 .V_Check V2.00&amp;lt;br&amp;gt;&lt;br /&gt;
setstate pulsedevice 2019-11-03 12:32:30 Trigger_log off&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Inbetriebnahme ==&lt;br /&gt;
Der Testraum 07_Puls enthält zwei konfigurierte MSwitch-Geräte, die die beabsichtigte Funktion zusammen bewirken. Pulse enthält die Logik, Pulsedevice dient der Statusausgabe des Generators. Als einziges muss in Pulse eine Auslösezeit in die obere Zeile (switch MSwitch on + execute &#039;cmd1&#039; at :) im Format hh:mm:ss geschrieben werden, um die Impulsfolge zu starten.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Pulse-Fenster-oben.png|mini|Pulse-Konfiguration 1. Teil]]&lt;br /&gt;
[[Datei:Pulse-Fenster2.png|mini|Pulse-Konfiguration 2. Teil]]&lt;br /&gt;
[[Datei:Pulsdevice.png|mini|Pulsdevice-Konfiguration]]&lt;br /&gt;
&lt;br /&gt;
Nach der Auslösung liefert das Pulsdevice eine endlose konfigurierbare Folge von Rechtecksignalen. Pulsdevice im Testraum in Aktion:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Pulsdevice .png||Pulsdevice im Testraum in Aktion]]&lt;br /&gt;
&lt;br /&gt;
== Funktionsbeschreibung ==&lt;br /&gt;
[[Datei:Kausakkette1.png|Trigger]]&amp;lt;br&amp;gt;&lt;br /&gt;
1. Auslösung des MSwitch-Gerätes &#039;Pulse&#039; beim Erreichen der angegebenen Triggertime,&amp;lt;br&amp;gt;&lt;br /&gt;
2. Aktivieren des 1. Befehlszweiges &#039;cmd1&#039; des MSwitch-Gerätes &#039;Pulse&#039;,&lt;br /&gt;
&lt;br /&gt;
[[Datei:Kausakkette2.png|Geräteauswahl]]&amp;lt;br&amp;gt;&lt;br /&gt;
3. Auswahl betroffener Geräte:  &#039;MSwitch_Self -&amp;gt; pulse&#039; und &#039;pulsedevice&#039;, Erzeugung je eines &#039;device action&#039;-Rahmens&lt;br /&gt;
  &lt;br /&gt;
[[Datei:Kausalkette3.png|Setzen der positiven Flanke des Rechtecksignals ]]&amp;lt;br&amp;gt;&lt;br /&gt;
4. unverzögertes Setzen des Status von &#039;pulsedevice&#039; auf &#039;on&#039;, positive Flanke des Rechtecksignals&lt;br /&gt;
&lt;br /&gt;
[[Datei:Kausalkette4.png|Negative Flanke des Ausgangssignals]]&amp;lt;br&amp;gt;&lt;br /&gt;
5. um die Länge von &#039;onpulse&#039; verzögertes Rücksetzen des Status von &#039;pulsdevice&#039;, negative Flanke des Rechtecksignals&lt;br /&gt;
&lt;br /&gt;
[[Datei:Kausalkette5.png|Pausenzeit]]&amp;lt;br&amp;gt;&lt;br /&gt;
6. um die Länge von &#039;offpulse&#039; verzögertes Ausführen von &#039;Set exec_cmd_1&#039;, Verweis auf ID1, Pausenzeit vor nächstem Impuls&lt;br /&gt;
&lt;br /&gt;
[[Datei:Kausalkette6.png|x]]&amp;lt;br&amp;gt;&lt;br /&gt;
5.???,&lt;br /&gt;
&lt;br /&gt;
== Anpassung an eigene Anforderungen ==&lt;br /&gt;
&lt;br /&gt;
Um eigene Geräte für die Ausgabe benutzen zu können, muss:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Attribut Switch_Ignore_Types = TYPE=MSwitch&amp;lt;/code&amp;gt;  auf&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Attribut Switch_Ignore_Types = notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
geändert werden. &lt;br /&gt;
&lt;br /&gt;
[[Datei:MSwitch Ignore Types geaendert.png|MSwitch_Ignore_Types geändert|938px]]&lt;br /&gt;
&lt;br /&gt;
Um den Verlust von Konfigurationsdaten zu vermeiden, lässt man das quickedit verriegelt und fügt eigene Zielgeräte per &#039;edit list&#039; hinzu.&lt;br /&gt;
[[Datei:Eigenes device.png|938px|Eigenes Device]]&lt;br /&gt;
&lt;br /&gt;
Die Bestätigung mit &#039;modify Devices&#039; erzeugt pro neuem Gerät einen &#039;device action&#039;-Rahmen, in den die Konfiguration von &#039;pulsedevice&#039; übernommen werden kann. &#039;Modify action&#039; übernimmt.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Deviceaction uebernehmen.png|938px|Deviceaction übernehmen]]&lt;br /&gt;
&lt;br /&gt;
Der zweite notwendige Action-Rahmen für das eigene Device wird per &#039;add action ..&#039; erzeugt.&lt;br /&gt;
&lt;br /&gt;
Das Attribut &#039;setlist&#039; erlaubt die leichte Anpassung der auswählbaren Impuls- bzw. Pausenzeiten. Hier können auch Dezimalbrüche wie 0,5 angegeben werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Bei der Arbeit.png|bei der Arbeit]]&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31650</id>
		<title>MSwitch</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31650"/>
		<updated>2019-11-08T22:36:47Z</updated>

		<summary type="html">&lt;p&gt;Maista: Neuer Link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[MSwitch]] ist ein Hilfsmodul, welches das Event- und/oder zeitgesteuerte Schalten von mehreren Devices oder das Ausführen von benutzerdefinierten Befehlssequenzen erlaubt. Hauptmerkmale sind die fast vollständige und die sehr umfangreiche Konfigurierbarkeit über das Webinterface.&lt;br /&gt;
&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=MSwitch&lt;br /&gt;
|ModType=h&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=98_MSwitch.pm&lt;br /&gt;
|ModOwner=Byte09}}&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz | RNTyp=y | RNText=Byte09: &#039;&#039;Die Grundidee zu MSwitch kam mir, weil ich bei der Arbeit mit FHEM für meinen Geschmack zu viele Module für die verschiedenen Aufgaben brauchte - zu allem Überfluss alle mit unterschiedlicher Syntax. Zwar ist DOIF hiervon ausgenommen (da hiermit wohl auch fast jede Aufgabe lösbar ist), aber ich konnte mich leider nicht daran gewöhnen und somit wurde jedes DOIF für mich zu einem echten Projekt. Was ich wollte war ein Modul, mit dem ich alles erledigen kann. Daher entschloss ich mich schon nach fast einem knappen Jahr FHEM-Nutzung mein eigenes Modul zu schreiben, welches diese Anforderung erfüllt. MSwitch beinhaltet die Funktionalität aller bisherigen Hilfsmodule wie z.B. Notify, Doif, Watchdog, Dummy,( ab Modulversion 2.2 auch Sequenz ) es lassen sich all deren Funktionen umsetzen.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;MSwitch wird permanent - vorrangig nach meinen Bedürfnissen - weiterentwickelt, gerne nehme ich aber auch Anregungen von anderen Nutzern auf.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Datei:1-2-3-4.png|rahmenlos]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Grundsätzliche Überlegungen ==&lt;br /&gt;
{{Randnotiz | RNTyp=y | RNText=Will man mehrere Geräte als gleichzeitige Auslöser betreiben, so muss das Device GLOBAL gewählt und die entsprechenden Geräte angegeben werden (dies erzeugt höhere Systemlast und ist nur im Expert-Modus verfügbar).}} &lt;br /&gt;
&lt;br /&gt;
1. Welches Gerät soll auslösen oder zu welcher Zeit soll eine Auslösung erfolgen? &lt;br /&gt;
[[Datei:MSwitch basic.svg|mini|240px|Stark vereinfachtes Struktogramm]]&lt;br /&gt;
Im Rahmen 1 des Webinterfaces lässt sich der Trigger (Auslöser) bzw. eine Zeitabhängigkeit konfigurieren:&lt;br /&gt;
&lt;br /&gt;
** jedes Event aus dem Eventmonitor,&lt;br /&gt;
** triggerunabhängige Zeiten, &lt;br /&gt;
** triggerunabhängige Zufallszeiten,&lt;br /&gt;
** triggerunabhängige Intervalle,&lt;br /&gt;
** Kombinationen aus Triggern und Zeiten.&lt;br /&gt;
&lt;br /&gt;
2. Welche Bedingungen sollen bei Auslösung erfüllt sein?&lt;br /&gt;
: Ersten Rahmen: Wenn diese Bedingungen erfüllt sind, werden Kommandos ausgelöst. Die Bedingungen werden im zweiten Teil des Webinterfaces eingegeben. Dabei unterscheidet das Modul zwischen zwei Kommando-Kanälen (cmd1 und cmd2) und den dazugehörigen Geräten.&lt;br /&gt;
&lt;br /&gt;
3. Welche Kommandos sollen ausgelöst werden?&lt;br /&gt;
: Im vierten Rahmen des Webinterfaces werden dann die konkreten Kommandos eingegeben. Man wählt dabei aus einer Liste wie auf der Geräteseite Kommandos aus. FreeCmd erlaubt geräteunabhängige Kommandos, beispielsweise reinen Perl-Code.&lt;br /&gt;
&lt;br /&gt;
4. Welche weiteren Bedingungen sollen noch gelten?&lt;br /&gt;
: Zusätzlich pro Gerät eine oder mehrere Instanzen des vierten Rahmens:&lt;br /&gt;
** ereignisgesteuerte Bedingungen,&lt;br /&gt;
** zeitgesteuerte Bedingungen,&lt;br /&gt;
** Verzögerungen,&lt;br /&gt;
** Wiederholungen etc.&lt;br /&gt;
&lt;br /&gt;
==Definition und Einrichtung =={{Randnotiz | RNTyp=y | RNText=Alle relevante Einstellungen werden in Readings und/oder Hashes gespeichert. Daher stehen relevanten Daten &#039;&#039;nicht&#039;&#039; in der fhem.cfg! Vielmehr finden sich diese Daten in der Datei fhem.save. Die Speicherung erfolgt durch den Befehl Fhemsave.&lt;br /&gt;
}}&lt;br /&gt;
Das MSwitch-Modul ist ohne weitere Voraussetzungen nutzbar und wird in der aktuellen Version über FHEM Update verteilt. MSwitch kann mehrere Devices gleichzeitig schalten. Diese Schaltungen befinden sich in den zwei möglichen Zweigen entsprechend der Kommandos cmd1 und cmd2. Die einzelnen Devices jedes Zweiges können mit weiteren Schaltbedingungen versehen werden (zeit- oder ereignisgesteuert). Das define eines MSwitch Devices generiert lediglich eine &#039;leere Hülle&#039;:&lt;br /&gt;
:&amp;lt;code&amp;gt;define &amp;lt;name&amp;gt; MSwitch&amp;lt;/code&amp;gt;&lt;br /&gt;
Es wird ein leeres Device angelegt, das dann komplett über das Webinterface konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
== Webinterface ==&lt;br /&gt;
MSwitch wird über das Webinterface eingerichtet. Es besteht aus vier Teilen. Änderungen in einem Abschnitt müssen auch dort gespeichert werden, bevor ein weiterer Teil bearbeitet wird, sonst gehen Änderungen verloren.{{Randnotiz | RNTyp=y | RNText=&amp;lt;code&amp;gt;attr &amp;lt;name&amp;gt; MSwitch_Help 1&amp;lt;/code&amp;gt; führt dazu, dass im Modul selber eine sehr umfangreiche kontextsensitive Hilfe in Form von Fragezeichensymbolen angezeigt wird.}} &lt;br /&gt;
&lt;br /&gt;
[[Datei:1-2-3-4.png|rahmenlos|Webinterface]]&lt;br /&gt;
=== Rahmen 1: Trigger Device und Trigger Time ===&lt;br /&gt;
==== Trigger Device ====&lt;br /&gt;
{{Randnotiz | RNTyp=y | RNText=Wenn das Attribut &#039;MSwitch_Expert&#039; gesetzt ist kann man &#039;GLOBAL&#039; auswählen. Dann werden &#039;&#039;&#039;alle&#039;&#039;&#039; von FHEM generierten Events durch das MSwitch Device weiterverarbeitet, eine weitere Begrenzung kann (und sollte) dann in einem folgenden Eingabefeld erfolgen, um die Systemlast zu reduzieren.&lt;br /&gt;
==== Trigger Device Global Whitelist ====&lt;br /&gt;
Damit kann die Liste eingehender Events weiter eingeschränkt werden. Sobald mindestens ein Eintrag vorhanden sind, werden nur noch Events der hier benannten Devices verarbeitet. Zulässig ind Devicenamen und DeviceTypen (z.B. TYPE=FS20). Mehrere Angaben sind durch Komma zu trennen.&lt;br /&gt;
&lt;br /&gt;
Im unten gezeigten Beispiel wurde GLOBAL gewählt, weil nicht ein einzelnes Device, sondern eine Kombination aus zwei Geräten auslösen soll. Es werden alle Ereignisse betrachtet, wobei die Whitelist dann auf die Devices Schlafzimmer (ein Temperaturmessgerät) und Schlafzimmerfenster (ein [[HM-Sec-SCo Tür-Fensterkontakt, optisch|optischer Kontakt]]) einschränkt.}}In diesem Feld wird das Device per Dropdownfeld gewählt, dessen Events eine Aktion auslösen sollen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:MSwitchWebinterface1.png|400px|thumb|right|Webinterface, oben]]&lt;br /&gt;
&lt;br /&gt;
==== Trigger Time ==== &lt;br /&gt;
Trigger time bietet die Möglichkeit einer zeitabhängigen Steuerung. Dazu wird in die &amp;quot;at&amp;quot;-Zeile ein Termin in der Form [STUNDEN:MINUTEN|TAGE] eingetragen. Die Tage werden ab Montag von 1-7 gezählt. Mehrere Zeitvorgaben können direkt hintereinander geschrieben werden. Beispiele:&lt;br /&gt;
* &amp;lt;code&amp;gt;[17:00|1][18:30|23]&amp;lt;/code&amp;gt; löst montags um 17 Uhr und dienstags sowie mittwochs um 18:30 Uhr aus.&lt;br /&gt;
* &amp;lt;code&amp;gt;[00:10*20:00-21:00]&amp;lt;/code&amp;gt; führt den Schaltbefehl von 20 Uhr bis 21 Uhr alle 10 Minuten aus.&lt;br /&gt;
* &amp;lt;code&amp;gt;[?20:00-21:00]&amp;lt;/code&amp;gt; schaltet zu einem zufälligen Zeitpunkt zwischen 20 und 21 Uhr einmalig.  &lt;br /&gt;
* &amp;lt;code&amp;gt;[20:00|$we]&amp;lt;/code&amp;gt; nur am Wochenende um 20:00 wird geschaltet.&lt;br /&gt;
&lt;br /&gt;
==== Trigger Conditions ====&lt;br /&gt;
&lt;br /&gt;
Optionale zusätzliche Bedingungen in diesem Feld gelten nur für auslösende Device Trigger. Trigger Times haben keinen Einfluss, es sei denn, das Attribut MSwitch_Condition_Time ist gesetzt. Man kann mit AND / OR verknüpfte Bedingungen für die Auslösung in an DOIF angelehnter Syntax angeben. Leere Felder werden ignoriert. Werden Readings mit Strings wie &#039;on&#039; oder &#039;off&#039; abgefragt, ist statt des Gleichheitszeichens &amp;quot;=&amp;quot; der Operator &amp;quot;eq&amp;quot; zu nutzen, der String muss in Anführungszeichen &amp;quot;&amp;quot; gesetzt werden. Beispiele:{{Randnotiz | RNTyp=y | RNText=Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (beispielsweise würde dann am Mittwoch noch der Schaltvorgang erfolgen, obwohl als Tagesvorgabe Dienstag gesetzt wurde).}} &lt;br /&gt;
* &amp;lt;code&amp;gt;[19:10-23:00] AND [Devicename:Reading] = 10&amp;lt;/code&amp;gt; beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
* &amp;lt;code&amp;gt;[19:10-23:00] OR [Devicename:Reading] eq &amp;quot;on&amp;quot;&amp;lt;/code&amp;gt; eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
* &amp;lt;code&amp;gt;[10:00-11:00|13]&amp;lt;/code&amp;gt; schaltet Montag und Mittwoch zwischen 10 Uhr und 11 Uhr.&lt;br /&gt;
* &amp;lt;code&amp;gt;[{ sunset() }-23:00]&amp;lt;/code&amp;gt; von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
* &amp;lt;code&amp;gt;{ !$we }&amp;lt;/code&amp;gt; löst den Schaltvorgang nur Werktagen an aus.&lt;br /&gt;
* &amp;lt;code&amp;gt;{ $we }&amp;lt;/code&amp;gt; löst den Schaltvorgang nur an Wochenenden, Feiertagen aus.&lt;br /&gt;
Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
=== Rahmen 2: Trigger Details ===&lt;br /&gt;
[[Datei:MSwitchWebinterface2.png|600px|thumb|right|Webinterface, Mitte]]&lt;br /&gt;
Der Inhalt des zweiten Rahmens wird mit dem gewählten Trigger aus dem ersten Rahmen initialisiert. Events können zugeordnet werden. Im Beispiel wird cmd1 ausgelöst, wenn das Fenster offen ist. Cmd2 wird bei Temperaturunterschreitung ausgelöst.&lt;br /&gt;
&lt;br /&gt;
==== execute ====&lt;br /&gt;
Diese vier Zeilen legen fest, welches ankommende Event welchen Befehlszweig auslösen soll. Die Event-Drop-Down-Liste enthält alle empfangenen Events dieses Devices. Fehlende Events können manuell hinzugefügt werden.&lt;br /&gt;
&lt;br /&gt;
* switch &amp;lt;MSwitch&amp;gt; on + execute &#039;cmd1&#039; -  MSwitch Statusänderung auf &#039;on&#039;; cmd1 soll ausgeführt werden&lt;br /&gt;
* switch &amp;lt;MSwitch&amp;gt; off + execute &#039;cmd2&#039; - MSwitch Statusänderung auf &#039;off&#039;; cmd2 soll ausgeführt werden; &lt;br /&gt;
* execute &#039;cmd1&#039; only - keine Statusänderung; cmd1 soll ausgeführt werden&lt;br /&gt;
* execute &#039;cmd2&#039; only - keine Statusänderung; cmd2 soll ausgeführt werden&lt;br /&gt;
&lt;br /&gt;
==== Save incomming events ====&lt;br /&gt;
Alle ankommenden Events der konfigurierten Geräte werden für die Dropdownlisten gespeichert. Nach erfolgreicher Konfiguration sollte diese Option entfernt werden, um die Datenmenge zu reduzieren. Falls das Device Events während der Konfiguration nicht liefert, können sie manuell als kommagetrennte Liste hinzugefügt werden.&lt;br /&gt;
&lt;br /&gt;
==== add event ====&lt;br /&gt;
{{Randnotiz | RNTyp=y | RNText=Falls auf &#039;GLOBALE&#039; Events getriggert wird, muss das auslösende Device vorangestellt werden:&lt;br /&gt;
- *                                                           - alle auftretende Events des entsprechenden Device&lt;br /&gt;
- device:reading:wert   (z.B. device:state:on )                      - nur für das Event &amp;quot;device:state:on&amp;quot;&lt;br /&gt;
- device:reading:*      (z.B. device:state:* )                       - Events &amp;quot;device:state:(on,off,etc.)&lt;br /&gt;
- device:reading:(wert1/wert2/wert3) (z.b. device:state:(left/right) - Events &amp;quot;device:state:left&amp;quot; oder &amp;quot;devicestate:right&amp;quot; etc.&lt;br /&gt;
&lt;br /&gt;
Das Device kann auch hier gegen &amp;quot;*&amp;quot; ersetzt werden (*:state:on). In diesem Fall erfolgt eine Aktion auf alle Events die z.B. &amp;quot;state:on&amp;quot; enthalten, egal welches Device triggert.&lt;br /&gt;
}} &lt;br /&gt;
* *                                                    - alle auftretende Events des entsprechenden Device&lt;br /&gt;
* reading:wert   (z.B. state:on )                      - nur auf das Event &amp;quot;state:on&amp;quot;&lt;br /&gt;
* reading:*      (z.B. state:* )                       - Events &amp;quot;state:(on,off,etc.)&lt;br /&gt;
* reading:(wert1/wert2/wert3) (z.b. state:(left/right) - Events &amp;quot;state:left&amp;quot; oder &amp;quot;state:right&amp;quot; etc.&lt;br /&gt;
==== test event ====&lt;br /&gt;
Stehen Events zur Auswahl, kann die Konfiguration getestet werden. Durch Klick wird das Event simuliert und die dafür definierte Aktion ausgelöst. &lt;br /&gt;
&lt;br /&gt;
==== apply filter to saved events ====&lt;br /&gt;
Beschreibung folgt???&lt;br /&gt;
&lt;br /&gt;
==== clear saved event ====&lt;br /&gt;
Es werden die nicht als Trigger wirkenden Events aus der Liste gelöscht.&lt;br /&gt;
&lt;br /&gt;
=== Rahmen 3: Affected devices ===&lt;br /&gt;
{{Randnotiz | RNTyp=y | RNText=In dem Auswahlfeld werden alle Devices angeboten, die eines der folgenden Kriterien erfüllen:&lt;br /&gt;
# Die Abfrage &amp;quot;set Device ?&amp;quot; liefert einen Befehlssatz&lt;br /&gt;
# Das Attribut &#039;webcmd&#039; des Devices enthält Einträge&lt;br /&gt;
# Das Attribut &#039;MSwitch_Activate_MSwitchcmds&#039; ist aktiviert und das Attribut &#039;MSwitchcmds&#039; des betreffenden Devices enthält einen Befehlssatz&lt;br /&gt;
&lt;br /&gt;
Einzige Ausnahme ist der erste Listeneintrag &#039;FreeCMD&#039;. Die Auswahl dieses Eintrages bietet später die Möglichkeit Befehle auszuführen, die nicht an ein Device gebunden sind. Der Code in einem FreeCmd kann entweder reiner FHEM-Code sein ( set device on ) oder reiner Perl-Code. Wenn es sich um reinen Perl-Code handelt, ist dieser in geschweifte Klammen zu setzen { Perl-Code }.&lt;br /&gt;
&lt;br /&gt;
}} &lt;br /&gt;
[[Datei:MSwitch_Screen_5.png|mini|rechts|affected devices]]&lt;br /&gt;
Auswahl der Devices, die auf die oben konfigurierten Events reagieren sollen. Um unbeabsichtigte Änderungen zu vermeiden ist die direkte Mehrfachauswahl gesperrt.&lt;br /&gt;
&lt;br /&gt;
=== Rahmen 4: Device Actions ===&lt;br /&gt;
&lt;br /&gt;
[[Datei:Webinterface3.png|mini|rechts|device_actions]]&lt;br /&gt;
Die auszuführenden Aktionen der im dritten Rahmen gewählten Geräte. Leere Felder werden ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== MSwitch cmd1/cmd2:  ====&lt;br /&gt;
{{Randnotiz | RNTyp=y | RNText=Im Beispiel befindet sich ein FreeCmd, mit dem beliebige Kommandos eingetragen werden können. Im abgebildeten Beispiel ist dies sogar selbst definierter Perl-Code (die Funktion DebianMail sendet eine Mail).&lt;br /&gt;
}} &lt;br /&gt;
Man wählt den gewünschten Befehl aus den gespeicherten verfügbaren Möglichkeiten des betreffenden Device aus. &lt;br /&gt;
&lt;br /&gt;
* Im Sonderfall FreeCmd wird der Befehl als String eingegeben. &lt;br /&gt;
* Das Attribut MSwitch_Extensions ergänzt die Schaltoption &#039;MSwitchToggle&#039; in der Liste, um die Toggle-Funktion bei Geräten die sie nicht von Haus aus anbieten nachzurüsten. &lt;br /&gt;
&lt;br /&gt;
{{Randnotiz | RNTyp=y | RNText=Je nach Attribut-Einstellungen werden Einträge aus entsprechenden &#039;webcmds&amp;quot; oder &#039;MSwitchcmds&#039; einbezogen. In Abhängigkeit des Befehls stehen unter Umständen weitere Felder oder Widgets zur Verfügung.&lt;br /&gt;
).&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 condition  ====&lt;br /&gt;
&lt;br /&gt;
{{Randnotiz | RNTyp=y | RNText=Bei der Abfrage von Readings nach Strings (on, off, etc.) ist statt &amp;quot;=&amp;quot; &amp;quot;eq&amp;quot; zu nutzen und der String muss in &amp;quot;x&amp;quot; gesetzt werden. Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&#039;&#039;&#039;Achtung:&#039;&#039;&#039; Bei Anwendung der geschweiften Klammern zur Einleitung eines Perl Ausdrucks ist unbedingt auf die Leerzeichen hinter und vor der Klammer zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (zum Beispiel würde auch am Mittwoch noch der Schaltvorgang erfolgen, wenn als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
}} &lt;br /&gt;
Die Ausführung der Befehle kann &#039;&#039;&#039;pro gewählten Gerät&#039;&#039;&#039; analog Rahmen 1 von weiteren Bedingungen abhängig gemacht werden. Es gelten die gleichen Regeln und Beispiele wie im &#039;Rahmen 1 Trigger Conditions&#039;. Sie können sinngemäß übernommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Variable &amp;lt;code&amp;gt;$EVENT&amp;lt;/code&amp;gt; enthält den auslösenden Trigger. Wenn unter &#039;Rahmen 1 Trigger Conditions&#039; ein Wildcard verwendet wurde, kann nun feingefiltert werden, indem das konkrete Ereignis angegeben wird. &lt;br /&gt;
&lt;br /&gt;
Beispiel: &amp;lt;code&amp;gt;[$EVENT] eq &amp;quot;state:on&amp;quot;&amp;lt;/code&amp;gt; würde den Kommandozweig nur dann ausführen, wenn der auslösende Trigger &amp;quot;state:on&amp;quot; war.&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 delay  ====&lt;br /&gt;
Ein Eintrag in diesem Feld führt zur verzögerten Ausführung des Befehls nach Eintreffen des Events. Dabei kann der Befehl ohne weitere Prüfung der Bedingung ausgelöst werden. Es ist aber auch möglich, dass die Bedingung bei Ausführung erneut geprüft wird. Die Zeitangabe muss im Format hh:mm:ss vorliegen. Einzelheiten enthält auch das Funktions-Struktogramm.&lt;br /&gt;
&lt;br /&gt;
Statt einer direkten Zeitangabe kann hier auch auf eine verwiesen werden, indem in der Form [NAME.reading] ein Reading eines Devices wie z.B. [dummy.state] angegeben wird.&lt;br /&gt;
&lt;br /&gt;
==== add action  ====&lt;br /&gt;
Mit diesem Button kann ein weiterer Rahmen 4 als Rahmen 4.1 für das gleiche Device angelegt werden, um z.B. einen weiteren Befehl gegebenenfalls zeitverzögert auszuführen.&lt;br /&gt;
&lt;br /&gt;
==== delete this action  ====&lt;br /&gt;
Mit diesem Button wird der gewählte Rahmen 4 für das Device gelöscht.&lt;br /&gt;
&lt;br /&gt;
==== check condition  ====&lt;br /&gt;
[[Datei:MSwitch_Screen_7.png|mini|rechts|check]]&lt;br /&gt;
Die angegebenen &#039;conditions&#039; werden in Zusammenhang mit ggf. ausgewählten Devices auf Syntax und Ergebnis geprüft. Es erfolgt eine Ausgabe des Prüfungsergebnisses.&lt;br /&gt;
&lt;br /&gt;
==== Repeat und Repeatdelay ====&lt;br /&gt;
&lt;br /&gt;
Die Felder &#039;Repeats&#039;, &#039;Repeatdelay in s&#039; und &#039;priority&#039; stehen zur Verfügung, wenn das Attribut MSwitch_Expert gesetzt wurde. Diese bewirken eine n-fache Wiederholung des gesetzten Befehls mit m Sekunden Verzögerung. Das Auswahlfeld &#039;priority&#039; erscheint bei jedem &#039;affectes device&#039;. So kann die Reihenfolge der Befehlsabarbeitung beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
== Erweiterte Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
=== Set-Befehle ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name !! class=&amp;quot;unsortable&amp;quot;  | Beschreibung &lt;br /&gt;
|-&lt;br /&gt;
|set active||Setzt das MSwitch-Device in den Status &#039;active&#039;.&lt;br /&gt;
|-&lt;br /&gt;
|set inactive||Setzt das Device in den Status &#039;inactive&#039;. Es werden keine Befehle mehr ausgeführt. Dieser Status entspricht dem Attribut &#039;disable&#039;, ist aber nicht mit dem roten Fragezeichen (fhem save) verbunden.&lt;br /&gt;
|-&lt;br /&gt;
|set on&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;off [&amp;lt;parameter&amp;gt;]||Setzt das Device in den Status &#039;on&#039; oder &#039;off&#039;. Alle Befehle der &#039;on/off-Zweige&#039; werden ausgeführt. Optional kann den Befehlen &#039;on&#039; und &#039;off&#039; ein weiterer Parameter mit übergeben werden. Dieser wird im Reading &#039;Parameter&#039; hinterlegt und es kann sofort in &#039;Freecmds&#039; oder &#039;Conditions&#039; darauf zugegriffen werden.&lt;br /&gt;
|-&lt;br /&gt;
|set reload_timer||Alle gesetzten Timer werden gelöscht und neu berechnet.&lt;br /&gt;
|-&lt;br /&gt;
|set change_renamed &amp;lt;oldname&amp;gt; &amp;lt;newname&amp;gt;||Sollten sich Devicenammen im ausführenden Teil geändert habe (affected Devices, Conditions, etc.) so kann das MSwitch mit diesem Befehl angepasst werden, ohne alle Einstellungen neu einstellen zu müssen.&lt;br /&gt;
|-&lt;br /&gt;
|set exec_cmd1 &amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; set exec_cmd1 ID [&amp;lt;ID&amp;gt;]||Bewirkt das sofortige Ausführen des entsprechenden Befehlszweiges. Bei Angabe einer ID werden nur die Befehle mit der entsprechenden ID ausgeführt.&lt;br /&gt;
|-&lt;br /&gt;
|set MSwitch_backup||Erstellt eine Backup-Datei aller MSwitch Devices unter ./fhem/MSwitch_backup.cfg. Daten dieser Datei können im Bedarfsfall für einzelne oder gleichzeitig alle MSwitch Devices wieder zurückgespielt (hergestellt) werden.&lt;br /&gt;
|-&lt;br /&gt;
|set del_delays &amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; set exec_cmd1 ID [&amp;lt;ID&amp;gt;]||Löscht alle anstehenden, verzögerten Befehle (delays).&lt;br /&gt;
|-&lt;br /&gt;
|set reset_cmd_count: 1&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;2||Löscht das entsprechende EVT_CMD_COUNT - Reading; entspricht damit einer Rückstellung auf &#039;0&#039;.&lt;br /&gt;
|-&lt;br /&gt;
|set fakeevent [&amp;lt;device&amp;gt;]:&amp;lt;reading&amp;gt;:&amp;lt;arg&amp;gt;||Beispiel: &amp;lt;device&amp;gt; fakeevent state:on&amp;lt;br&amp;gt;&lt;br /&gt;
Das MSwitch Device reagiert so, als wäre statt des internen &amp;quot;fakes-Befehls&amp;quot; ohne FHEM-Systembeeinflussung dieses Event tatsächlich vom triggernden Gerät generiert worden. &lt;br /&gt;
&lt;br /&gt;
Der Name (&amp;lt;device&amp;gt;) muss bei GLOBALEN Triggern mit angegeben werden, sonst wird das Device automatisch gesetzt.&lt;br /&gt;
Um z.B. einen Watchdog zu realisieren ist es eventuell nötig, dass sich das MSwitch Device mit einem bestimmten Event selber neu triggert - ggf. mit einem entsprechenden Delay Affected Device. Bei dem Einsatz dieser Möglichkeit sollte das Attribut &#039;MSwitch_Safemode&#039; UNBEDINGT aktiviert sein, da &#039;Experimente&#039; hier schnell in einer Endlosschleife enden können, die nur durch ein Reboot unterbrochen werden kann. Möglicherweise steht dieser Befehl zukünftig nur noch zur Verfügung, wenn Safemode aktiviert ist.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Get-Befehle ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name !! class=&amp;quot;unsortable&amp;quot;  | Beschreibung &lt;br /&gt;
|-&lt;br /&gt;
|get show_timer [&amp;lt;show&amp;gt;&amp;lt;delete&amp;gt;]||&lt;br /&gt;
;Show&lt;br /&gt;
:Zeigt alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren.&lt;br /&gt;
;Delete&lt;br /&gt;
:Löscht alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren. Schaltbefehle basierend auf rein zeitabhängigen Angaben werden neu berechnet und gesetzt.&lt;br /&gt;
|-&lt;br /&gt;
|get restore_MSwitch_data [&amp;lt;this_device&amp;gt;&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;&amp;lt;all_devices&amp;gt;]||&lt;br /&gt;
;this_device&lt;br /&gt;
:Stellt die Daten des Devices aus der Backupdatei wieder her, sofern diese in der Backupdatei gefunden werden (gesucht wird hier nach dem Namen des Devices).&lt;br /&gt;
;all_devices&lt;br /&gt;
:Stellt die Daten aller MSwitch Devices wieder her, sofern diese in der Backupdatei vorhanden sind. Diese Aktion kann einige Zeit in Anspruch nehmen und wird daher im Hintergrund (nonblocking) ausgeführt. Nach Beendigung erfolgt eine Benachrichtigung.&lt;br /&gt;
Die Devices sind nach einem Restore funktionsfähig. Empfohlen wird ein Neustart von FHEM..&lt;br /&gt;
|-&lt;br /&gt;
|get_config||Zeigt die Konfigurationsdatei des MSwitchdevices an; diese kann in dem Fenster editiert werden. Das sollte nur von erfahrenen Usern getan werden! Im Normalfall sollte das Device nur über die Weboberfläche konfiguriert werden und eine falsche Konfiguration kann hier zu einem FHEM Absturz führen.&lt;br /&gt;
|-&lt;br /&gt;
|get_support_info||Öffnet ein Fenster mit einer formatierten Ansicht aller Einstellungen des Devices. Bei Supportanfragen sollte dieses immer mit geposted werden.&lt;br /&gt;
|-&lt;br /&gt;
|get_MSwitch_preconf||Lädt vorkonfigurierte MSwitch-Devices. Diese Option ist nur dann vorhanden, wenn das Aktualisieren dieser vorkonfigurierten Devices im FHEM Update aktiviert ist.&lt;br /&gt;
Diese kann durch ein einmaliges Update erfolgen mit:&lt;br /&gt;
:&amp;lt;code&amp;gt;update all https://raw.githubusercontent.com/Byte009/MSwitch_Addons/master/controls_mswitchaddons.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Attribute ===&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name !! class=&amp;quot;unsortable&amp;quot;  | Beschreibung &lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Debug &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;2&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;3&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;4&amp;gt;||&lt;br /&gt;
0 - Abgeschaltet&amp;lt;br&amp;gt;&lt;br /&gt;
1 - Schaltet Felder zum testen der Conditionstrings an&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Alle ausgehenden Befehle werden nur simuliert und nicht ausgeführt. Der Inhalt der Protokolldatei wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
3 - Es erfolgt eine Protokollierung in einer separaten Datei. Diese wird direkt im Device angezeigt.&amp;lt;br&amp;gt;&lt;br /&gt;
4 - erweitertes Debugfür Entwickler mit wechselnden Funktionen&amp;lt;br&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Expert &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt;||&lt;br /&gt;
* In der Liste der möglichen Trigger erscheint das Selectfeld &#039;GLOBAL&#039;. Dieses ermöglicht das Setzen eines Triggers auf alle Events und damit nicht nur auf einzelne Devices. In einem weiteren Feld kann eine weitere Selektion der triggernden Events erfolgen.&lt;br /&gt;
&lt;br /&gt;
* Die Felder &#039;Repeats&#039; und &#039;Repeatdelay in s&#039; stehen zur Verfügung. Dies bewirkt eine n-fache Wiederholung des gesetzten Befehls mit m Sekunden Verzögerung.&lt;br /&gt;
&lt;br /&gt;
* Das Auswahlfeld &#039;priority&#039; erscheint bei jedem &#039;affectes device&#039;. So kann die Reihenfolge der Befehlsabarbeitung beeinflusst werden.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Sequenz &amp;lt;Suchmuster&amp;gt; ??? ||&lt;br /&gt;
Eine Schaltsequenz kann durch ein oder mehrere durch &#039;/&#039; getrennte Suchmuster angegeben werden. Die Angabe muss folgende Syntax haben:&lt;br /&gt;
:&amp;lt;code&amp;gt;Device1:reading1:event1 Device1:reading1:event1-2 Device1:reading1:event1-3/..../....&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel: &amp;lt;code&amp;gt;Dummy:state:on Dummy:state:off Dummy:state:on&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erkennt das Device dieses Suchmuster in den Schaltvorgängen des Devices (Dummy), wird das Reading &amp;quot;SEQUENCE&amp;quot; auf &amp;quot;match&amp;quot; gesetzt, das Reading &amp;quot;SEQUENCE_NUMBER&amp;quot; auf die Nummer der gefundenen Sequenz, wenn es mehrere Suchmuster gibt. Beide Readings können in den &amp;quot;Conditions&amp;quot; eines Schaltbefehles abgefragt werden. Eine Angabe muss in folgendem Format gemacht werden:&lt;br /&gt;
:&amp;lt;code&amp;gt;on/off/state/suchmuster1/suchmuster2&amp;lt;/code&amp;gt;, wobei die letzten drei Angaben optional sind.&lt;br /&gt;
&lt;br /&gt;
Funktion: Bei Ausführung des Befehls wird das Gerät &#039;on&#039; oder &#039;off&#039; geschaltet (on/off), Voraussetzung ist, dass der &#039;state&#039; dieses Gerätes auch den &#039;state on&#039; oder &#039;off&#039; annimmt. Sollte dieses nicht der Fall sein, so kann mit dem Feld &#039;state&#039; angegeben werden, in welchem Reading der aktuelle Status vorkommt und wie dieser lautet (suchmuster1/suchmuster2). Dieses &#039;state&#039; kann mehrere Angaben enthalten, das Vorkommen der Suchmuster ist aber Voraussetzung.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Sequence_time &amp;lt;Zeit in Sekunden&amp;gt;||Maximalzeit in Sekunden, um eine Sequenz vollständig auszuführen. (Was wenn diese Zeit überschritten wird???)&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Extensions &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt;||Es wird zusätzlich zu &#039;on&#039; und &#039;off&#039; die Schaltoption &#039;MSwitchToggle&#039; in der Liste angeboten, um die Toggle-Funktion bei Geräten die sie nicht von Haus aus anbieten nachzurüsten.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Delete_Delays &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt;||Eins bewirkt das Löschen aller anstehende Delays bei dem Auftreten eines erneuten passenden Events. Bei der Option &#039;0&#039; bleiben bereits gesetzte Delays aus einem vorher getriggerten Event erhalten und werden ausgeführt. Empfohlene Einstellung: 1&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Include_Devicecmds &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt;||Bewirkt die Aufnahme aller Devices die bei Abfrage mit &#039;set DEVICE ?&#039; einen eigenen Befehlssatz liefern in die Auswahlliste &#039;Affected Devices&#039;. Bei Option &#039;0&#039; werden diese Devices in der Liste nicht mehr angeboten. Empfohlene Einstellung: 1&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Include_Webcmds &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt;||Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut Webcmd hinterlegt haben. Die in Webcmd hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten. Bei gesetzter Option &#039;0&#039; werden diese Devices nicht mehr angeboten, es sei denn, sie liefern mit &#039;set DEVICE ?&#039; einen eigenen Befehlssatz. Empfohlene Einstellung: 0, Einsatz nach Bedarf.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Activate_MSwitchcmds &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt;||Fügt jedem vorhandenen Device das Attribut &#039;MSwitchcmd&#039; hinzu.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Include_MSwitchcmds &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt; ||Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut MSwitchcmds hinterlegt haben. Die in MSwitchcmds hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten. Bei gesetzter Option &#039;0&#039; werden diese Devices nicht mehr angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz mit &#039;set DEVICE ?&#039; liefern. Empfohlene Einstellung: 0, Einsatz nach Bedarf.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Lock_Quickedit &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt;||Voreinstellung für die Auswahlliste &#039;Affected Devices&#039;. Bei der Option &#039;1&#039; ist diese voreingestellt gesperrt und kann nur über einen zusätzlichen Button geändert werden, um versehentliche Änderungen zu vermeiden. Die Auswahl einer Option ohne betätigte &amp;lt;Strg&amp;gt;-Taste bewirkt das Löschen aller bereits gesetzten Optionen. Empfohlene Einstellung: 1&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Startdelay &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;10&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;20&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;30&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;60&amp;gt; ||MSwitch ignoriert nach einem FHEM-Neustart für die angegebene Zeit in Sekunden alle eingehenden Events um u.a. Startverzögerungen zu vermeiden. Bei nicht gesetztem Attribut gilt hier eine Zeit von 30 Sekunden. Diese sollte auch nur in Ausnahmefällen geändert werden. Empfohlene Einstellung: 30&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Ignore_Types||Beinhaltet eine durch Leerzeichen getrennte Liste von Device-&#039;&#039;Typen&#039;&#039; welche nicht geschaltet werden oder nicht geschaltet werden können. Sie werden dann in den Auswahllisten &#039;&#039;nicht&#039;&#039; dargestellt, um die Auswahllisten übersichtlich zu halten.Voreinstellung: notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul. &lt;br /&gt;
&lt;br /&gt;
???Wenn statt des Devicetyps ein devspec z.B. &amp;quot;TYPE=watchdog&amp;quot; angegeben wird, ist zu beachten, dass alle Geräte in die Ignoreliste einbezogen werden, die NICHT der devspec entsprechen. Weiterhin muss die devspec in Anführungszeichen gesetzt werden!???&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Trigger_Filter  ||Beinhaltet eine kommagetrennte Liste von Events, die im Falle ihres Eingangs unberücksichtigt und ungespeichert bleiben. Wildcards wie &#039;*&#039; können angegeben werden. Empfohlene Einstellung: -&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Wait &amp;lt;n in Sekunden&amp;gt;||Bei gesetztem Attribut nimmt das MSwitch Device für den eingestellten Zeitraum keine Befehle mehr entgegen und ignoriert eingehende Events.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Event_Id_Distributor||??? Voraussetzung ist, dass das Attribut &#039;MSwitchExpert&#039; auf &#039;1&#039; gesetzt ist. Es können auslösende Events auf ID-Aktionen umgeleitet werden. Sollte bei den &#039;trigger details :&#039; in einem Zweig ( cmd1 ) z.B. auf mehrere Events getriggert werden (regex z.B. state:(on|off)) so werden für beide Events jeweils der Zweig &#039;cmd1&#039; - alle  Aktionen ohne ID - ausgeführt. Durch entsprechende Einträge kann für entsprechende Events auf eine Aktion umgeleitet werden, für die eine ID definiert ist. Die Syntax lautet: &amp;lt;code&amp;gt;state:on=&amp;gt;cmd1 ID 1,2&amp;lt;/code&amp;gt; Entsprechend werden bei auslösendem Event &#039;state:on&#039; nur die Aktionen aus cmd1 mit den IDs 1 und 2 ausgeführt. Mehrere Angaben sind durch new Line zu trennen. ???&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Selftrigger_always &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt; ||(dieses Attribut steht ab Modulversion 2.5 zur Verfügung)&lt;br /&gt;
&lt;br /&gt;
Die Aktivierung dieses Attributes &#039;1&#039; bewirkt, dass alle SET Aktionen des Devices einen internen Event ohne Auswirkungen auf das FHEM-System auslösen, auf die das Device selber reagiert. Diese Option kann zusätzlich zu einem vorhandenen Trigger aktiviert werden. Auftretende auswertbare interne Events haben immer folgendes Format: &lt;br /&gt;
MSwitch_Self:aktion:wert &lt;br /&gt;
MSwitch_Self:pct:100&lt;br /&gt;
Es werden nur interne Events für set-Aktionen ausgelöst, die im Attribut setlist hinterlegt sind. Der &#039;wait&#039; Befehl/Attribut hat keine wirkung.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Mode &amp;lt;Notify&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;Full&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;Toggle&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;Dummy&amp;gt; ||Schaltet das Modul zwischen angepassten Weboberflächen-Modi um.&lt;br /&gt;
&lt;br /&gt;
Notify&lt;br /&gt;
Das Device kann nicht manuell umgeschaltet werden. Es gibt nur die zwei ausführbaren Zweige &amp;quot;execute &#039;cmd1&#039; commands&amp;quot; und &amp;quot;execute &#039;cmd2&#039; commands&amp;quot;. Der Status des Devices wird nicht als &#039;on&#039; oder &#039;off&#039; angezeigt, sondern lediglich als &#039;active&#039; Dieser Mode ist ähnlich zu einem FHEM-Notify.&lt;br /&gt;
&lt;br /&gt;
Full&lt;br /&gt;
Es stehen alle Funktionen zur Verfügung.&lt;br /&gt;
Toggle&lt;br /&gt;
Sehr vereinfachter Mode. Es stehen keine verschiedenen Zweige zur Verfügung. Hier ist das Device manuell schaltbar und wird bei jedem definierten Event &#039;umgeschaltet&#039;, ??? entsprechend definierte Befehle für &#039;cmd1&#039; oder &#039;cmd2&#039; werden ausgeführt. ???&lt;br /&gt;
Dummy&lt;br /&gt;
ACHTUNG: Funktionsänderung mit V2.61 Der Mode &#039;Dummy&#039; ist ein eingeschränkter Modus. Dieser bietet die Funktionalität eines Dummys kombiniert mit der Funktionalität eines Notifys und kann somit die gerne genutzte Kombination Dummy-Notify gegen ein Device ersetzen. Der Dummy-Mode kann nur in einem neu angelegten leeren MSwitch aktiviert und auch nicht wieder verlassen werden! Sobald ein angelegtes MSwitch einmal verändert wurde (modify trigger etc.) sind Umschalt-Optionen nicht mehr verfügbar.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Condition_Time &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt; ||In der Grundeinstellung &#039;0&#039; werden für das zeitgesteuerte Schalten keine definierten Conditionen im Feld &#039;Trigger condition&#039; überprüft, sondern die Schaltbefehle werden in jedem Fall ausgeführt. Mit der Einstellung &#039;1&#039; wird diese Überprüfung wie für Events zugeschaltet.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Random_Time &amp;lt;HH:MM:SS-HH:MM:SS&amp;gt; || Bei Aktivierung wird vor jedem Ausführen eines verzögerten Befehls (Delay) eine Zufallszeit generiert, die im Rahmen der hier angegebenen Zeitspanne liegt. Auf diese Zufallszahl kann in den Delays zugegriffen werden, durch die Angabe &#039;[random]&#039; statt einer direkten Zeitangabe. Bei nicht gesetztem Attribut ergibt die Angabe von &#039;[random]&#039; immer &#039;00:00:00&#039;&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MMSwitch_Random_Number &amp;lt;n&amp;gt; ||Bei Aktivierung dieses Attributes mit einer beliebigen ganzen Zahl, werden vom Device die zwei Readings  &#039;RandomNr&#039; und &#039;RandomNr1&#039; und mit Werten zwischen null und n angelegt. RandomNr wird vor jedem Ausführen eines Befehls, auch für unterschiedliche Geräte in einem Durchgang, neu generiert. RandomNr1 bleibt nach der Initialisierung konstant. Wenn auf dieses Readings in einer Condition mit z.B. &#039;[$NAME:ReadingNr1] = 1&#039; zugegriffen wird, wird der Befehl nur ausgeführt, wenn ReadingNr1 gerade = 1 ist. Der Befehl wird somit nur mit einer Wahrscheinlichkeit von eins zu n ausgeführt.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Reset_EVT_CMD1(2)_COUNT ||Bei Aktivierung dieses Attributes steht in den Readings das Reading &#039;EVT_CMD1_COUNT&#039; bzw. &#039;EVT_CMD2_COUNT&#039; zur Verfügung. Dieses kann in den Conditions genutzt werden, um z.B. nur bei jedem x-ten Eintreffen eines auslösenden Events einen Befehl auszuführen. Bei jedem Eintreffen eines gültigen Events werden die Zähler um 1 erhöht (für den jeweiligen Zweig). Ist hier der Wert &#039;0&#039; eingetragen, wird der Zähler fortlaufend (endlos) erhöht. Wird ein Wert größer 0 eingetragen, wird der Zähler mit Erreichen dieses Wertes automatisch wieder auf Null gesetzt. Mit Löschen dieses Attributes werden die entsprechenden Readings ebenfalls gelöscht.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Safemode &amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt; ||Bietet einen gewissen Schutz vor falschen Konfigurationen und dadurch entstehenden Endlosschleifen. Bei aktiviertem Attribut &#039;1&#039; beendet das Modul Endlosschleifen eines Devices. In diesem Fall erfolgt ein Logeintrag und das Device wird per Attribut auf &#039;Disabled&#039; gesetzt. Es wird ein letztes Event generiert, auf das reagiert werden kann &amp;lt;code&amp;gt;2018-05-31 09:39:21 MSwitch &amp;lt;NAME&amp;gt; Safemode: on&amp;lt;/code&amp;gt; Im Webinterface erfolgt bei betroffenem Device ein entsprechender Hinweis. In der Grundkonfiguration ist dieses Attribut nicht gesetzt. Es empfiehlt sich aber, bei neuen bzw. komplizierten Devices, dieses zumindest anfänglich zu aktivieren.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Read_Log&amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt; ||Ermöglicht den Zugriff auf das Logfile als Trigger.&lt;br /&gt;
&lt;br /&gt;
* Bei aktiviertem Attribut enthält die Auswahl des Triggerdevices die Option &#039;LOGFILE&#039;. Bei dieser Auswahl werde alle Logeinträge erkannt und in ein internes Event umgewandelt, auf das regiert werden kann.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl &#039;GLOBAL&#039; im &#039;Trigger_Device&#039; wird auf ALLE Events und alle Logeinträge reagiert.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl eines bestimmten Devices im &#039;Trigger_Device&#039; wird auf alle Events  und auf alle Logeinträge des gewählten Devices reagiert. Der im Logeintrag vorhandene Devicename ist Bedingung für die Funktion.&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Help&amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt; ||Schaltet Hilfebuttons zu den einzelnen Eingabefeldern an oder aus.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Comments&amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt; ||Schaltet Kommentarfelder zu den einzelnen &#039;affected_devices an.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_generate_Events&amp;lt;0&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;1&amp;gt; ||Reduziert bei Einstellung &#039;1&#039; die vom MSwitch-Devices erzeugten Events auf ein Minimum. Insbesondere bei Verwendung von &#039;MSwitch_Read_Log&#039; zu empfehlen.&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Startdelay||???Bestimmt die Verzögerungszeit des MSwitches nach FHEM-Start in Sekunden. In diesem Zeitraum reagiert das Device nicht auf Events. Die Vorgabe ist hier zehn Sekunden. Diese wird auch dann angenommen, wenn das Attribut nicht gesetzt ist.??? (Hatten wir das nicht schon?)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|MSwitch_Inforoom  ||Mit diesem Attribut wird die Raumansicht eines mit dem Attribut bestimmten Raumes verändert. Dadurch sollen die wichtigsten Informationen aller MSwitch-Devices auf eine Seite dargestellt werden. Zur Nutzung sollten alle MSwitch-Devices (zusätzlich) in einen Raum sortiert werden und dieser Raum im Attribut eingestellt werden.&lt;br /&gt;
&lt;br /&gt;
Wichtig: Eine Änderung dieses Attributes bewirkt immer eine Änderung dieses Attributes in &#039;&#039;allen&#039;&#039; MSwitch devices: Es muss nur in einem Device gesetzt oder gelöscht werden um alle Devices zu erfassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
MSwitch_Screen_1.png|Raumansicht des Raumes MSwitch mit gesetztem Attribut &#039;MSwitch&#039;&lt;br /&gt;
MSwitch_Screen_2.png|Raumansicht des Raumes MSwitch ohne gesetztes Attribut&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es werden folgende Informationen bereitgestellt:&lt;br /&gt;
* Infobutton zeigt den im Device gespeicherten Textes des Attributes &#039;comment&#039;&lt;br /&gt;
* Device und Events, die das Device triggern&lt;br /&gt;
* Zeiten, zu denen verschiedene Zweige des Devices ausgeführt werden&lt;br /&gt;
* Devices, die durch das MSwitch Device geschaltet werden&lt;br /&gt;
* State des Devices&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Integrierte Funktionen ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name !! class=&amp;quot;unsortable&amp;quot;  | Beschreibung &lt;br /&gt;
|-&lt;br /&gt;
|Average||???&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
|Difference||&lt;br /&gt;
* Syntax: [DIFF&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;differenz&amp;gt;&lt;br /&gt;
* Beispiel: [DIFF2:countdown] &amp;gt; 0&lt;br /&gt;
* Reading: entspricht dem getriggerten Reading.&lt;br /&gt;
* Wert: gespeicherter Wert (in diesem Fall der vorletzte).&lt;br /&gt;
* Differenz: geforderte Differenz zwischen aktuellem und vorletztem Wert.&lt;br /&gt;
* Schaltung erfolg wenn diese Bedingung &#039;wahr&#039; ist.&lt;br /&gt;
Folgende Readings werden zur Verfügung gestellt:&lt;br /&gt;
* DIFFERENCE (true/false) - Schaltbedingung erkannt ja/nein&lt;br /&gt;
* DIFFDIRECTION (up/down) - Richtung der erkannten Bedingung (steigend/fallend)&lt;br /&gt;
|-&lt;br /&gt;
|Increase||???&lt;br /&gt;
|-&lt;br /&gt;
|Tendency||&lt;br /&gt;
*Syntax: [TEND&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;Mindestwert&amp;gt;&lt;br /&gt;
*Beispiel: [TEND2:countdown] &amp;gt; 2&lt;br /&gt;
*Reading: entspricht dem getriggerten Reading.&lt;br /&gt;
*Wert: Es wird jeweils der Durchschnitt von 2 Wertepaaren gebildet. In diesem Fall werden die letzten 4 Werte herangezogen. Paar 1 = Aktueller und letzter Wert, Paar 2 = Die 2 vorherigen Werte. Bei TEND3 werden die letzten 6 Werte zur Paarbildung genutzt.&lt;br /&gt;
*Mindestwert: Der Wertunterschied zwischen den Wertepaaren, der minimal erreicht sein muss, um eine Tendenz zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Rechenzeichen (&amp;gt;&amp;lt;):&lt;br /&gt;
Dieses ist hier nicht als Rechenzeichen zu werten, sonder als Tendenz-Anzeige. ( &amp;lt; es wird nach fallender Tendenz gesucht / &amp;gt; sucht nach steigender Tendenz).&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolgt einmalig bei Erkennung der gesuchten Tendenz.&lt;br /&gt;
Danach erfolgt keine Schaltung mehr, solange bis eine Tendenz-Umkehr erfolgt ist.&lt;br /&gt;
Erst dann erfolgt wieder eine Schaltung bei erneuter Tendenz-Umkehr in gesuchte Richtung.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Funktions-Struktogramm ==&lt;br /&gt;
[[Datei:MSwitch full.svg|Struktogramm des Funktionsprinzips]]&lt;br /&gt;
&lt;br /&gt;
== Anwendungs-Beispiele ==&lt;br /&gt;
&lt;br /&gt;
=== [[Blinken - Rechteckgenerator]] ===&lt;br /&gt;
=== [[Blinken - Impulsgenerator mit variablem Tastgrad]] ===&lt;br /&gt;
=== [[Linearschalter]] ===&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Thread über das Modul im {{Link2Forum|Topic=86199|LinkText=FHEM Forum}}&lt;br /&gt;
* {{Link2Forum|Topic=100119|Message=936495|LinkText=Gäste-WLAN der Fritzbox auswerten und Login per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=86199|Message=930133|LinkText=Schalten von vier Kanälen mit einem MSwitch-Device}}&lt;br /&gt;
* {{Link2Forum|Topic=99219|Message=926652|LinkText=Batterie-Überwachung. 1xTäglich per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=101091|Message=945389|LinkText=Licht (Alarm) in einem bestimmten Zeitraum schalten}}&lt;br /&gt;
* {{Link2Forum|Topic=100949|Message=944284|LinkText=Über Dummy-Schalter ein Timer (EIN/AUS) aktivieren}}&lt;br /&gt;
* {{Link2Forum|Topic=103083|Message=967710|LinkText=Ladezeit von Akku ermitteln u. Steckdose entsprechend schalten}}&lt;br /&gt;
* {{Link2Forum|Topic=86199|Message=990265|LinkText=Bewegungsmelder}}&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31481</id>
		<title>MSwitch</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31481"/>
		<updated>2019-11-01T20:15:46Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* MSwitch_Startdelay */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[MSwitch]] ist ein Hilfsmodul, welches das Event- und/oder zeitgesteuerte Schalten von mehreren Devices oder das Ausführen von benutzerdefinierten Befehlssequenzen erlaubt.&lt;br /&gt;
&lt;br /&gt;
Die Stärke bzw. das Unterscheidungsmerkmal dieses Moduls liegt in der Konfigurierbarkeit über ein Webinterface. Diese Konfiguration kann jederzeit geändert oder erweitert werden. &lt;br /&gt;
&lt;br /&gt;
Byte09: &#039;&#039;Die Grundidee zu MSwitch kam mir, weil ich bei der Arbeit mit FHEM für meinen Geschmack zu viele Module für die verschiedenen Aufgaben brauchte - zu allem Überfluss alle mit unterschiedlicher Syntax. Zwar ist DOIF hiervon ausgenommen (da hiermit wohl auch fast jede Aufgabe lösbar ist), aber ich konnte mich leider nicht daran gewöhnen und somit wurde jedes DOIF für mich zu einem echten Projekt. Was ich wollte war ein Modul, mit dem ich alles erledigen kann. Daher entschloss ich mich schon nach fast einem knappen Jahr FHEM-Nutzung mein eigenes Modul zu schreiben, welches diese Anforderung erfüllt. MSwitch beinhaltet die Funktionalität aller bisherigen Hilfsmodule wie z.B. Notify, Doif, Watchdog, Dummy,( ab Modulversion 2.2 auch Sequenz ) es lassen sich all deren Funktionen umsetzen.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;MSwitch wird permanent - vorrangig nach meinen Bedürfnissen - weiterentwickelt, gerne nehme ich aber auch Anregungen von anderen Nutzern auf.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=MSwitch&lt;br /&gt;
|ModType=h&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=98_MSwitch.pm&lt;br /&gt;
|ModOwner=Byte09}}&lt;br /&gt;
&lt;br /&gt;
== Grundsätzliche Überlegungen ==&lt;br /&gt;
Um das Modul zu nutzen, muss man zuerst folgende Fragen beantworten:&lt;br /&gt;
&lt;br /&gt;
* Welches Gerät soll auslösen oder zu welcher Zeit soll eine Auslösung erfolgen.&lt;br /&gt;
: Dies ist der Trigger. Jedes Event aus dem Eventmonitor kann als Trigger dienen. Will man mehrere Geräte als gleichzeitige Auslöser betreiben, so muss das Device GLOBAL gewählt und die entsprechenden Geräte angegeben werden (dies erzeugt höhere Systemlast und ist nur im Expert-Modus verfügbar). Weiterhin kann auch zu fest definierten Zeiten, Zufallszeiten oder Intervallen, unabhängig von einem Trigger, geschaltet werden; auch eine Kombination beider Varianten ist möglich. Diese Einstellungen erfolgen im ersten Teil des Webinterfaces.&lt;br /&gt;
&lt;br /&gt;
* Welche Bedingungen sollen bei Auslösung erfüllt sein?&lt;br /&gt;
: Wenn diese Bedingungen erfüllt sind, werden Kommandos ausgelöst. Die Bedingungen werden im zweiten Teil des Webinterfaces eingegeben. Dabei unterscheidet das Modul zwischen zwei Kommando-Kanälen (cmd1 und cmd2) und den dazugehörigen Geräten.&lt;br /&gt;
&lt;br /&gt;
* Welche Kommandos sollen ausgelöst werden?&lt;br /&gt;
: Im dritten Teil des Webinterfaces werden dann die konkreten Kommandos eingegeben. Typischerweise wählt man dabei aus einer Liste der Kommandos aus, die die zugehörigen Geräte insgesamt aufweisen (also so, wie man auf den Geräteseiten selber Kommandos auswählt). Es gibt zudem ein so genanntes FreeCmd, das ein Geräteunabhängiges Kommando zulässt, beispielsweise reinen Perl-Code.&lt;br /&gt;
&lt;br /&gt;
* Welche weiteren Bedingungen sollen noch gelten?&lt;br /&gt;
: Hier sind Ereignisgesteuerte wie auch Zeitgesteuerte Bedingungen möglich. Diese Bedingungen werden auch in dem dritten Teil des Webinterfaces eingetragen. So sind Verzögerungen und Wiederholungen und weitere Bedingungen möglich.&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen, Installation und Grundbefehle ==&lt;br /&gt;
Das MSwitch-Modul ist ohne weitere Voraussetzungen nutzbar und wird derzeit in der Version 2.08 über FHEM Update verteilt. &lt;br /&gt;
&lt;br /&gt;
=== Definition und Einrichtung ===&lt;br /&gt;
Mit Hilfe von MSwitch kann man mehrere Devices gleichzeitig schalten. Diese Schaltungen befinden sich in zwei möglichen Zweigen bei MSwitch. Dabei unterscheidet man im Modul zwischen den beiden Kommandos cmd1 und cmd2. Die zu einem Kommando gehörenden Geräte werden wir auch Zweig nennen. Die einzelnen Devices jedes Zweiges können mit weiteren Schaltbedingungen versehen werden (zeit- oder ereignisgesteuert). &lt;br /&gt;
&lt;br /&gt;
Folgende Möglichkeiten zum definieren des MSwitch Devices stehen zur Verfügung:&lt;br /&gt;
:&amp;lt;code&amp;gt;define &amp;lt;name&amp;gt; MSwitch&amp;lt;/code&amp;gt;&lt;br /&gt;
Es wird ein leeres Device angelegt, das dann komplett über das Webinterface konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das define eines MSwitch Devices generiert lediglich eine &#039;leere Hülle&#039;. Alle relevante Einstellungen werden in Readings und/oder Hashes gespeichert. Daher stehen relevanten Daten &#039;&#039;nicht&#039;&#039; in der fhem.cfg! Vielmehr finden sich diese Daten in der Datei fhem.save (die Speicherung erfolgt durch den Befehl Fhemsave).&lt;br /&gt;
&lt;br /&gt;
=== set-Befehle ===&lt;br /&gt;
Es sind derzeit die folgenden set-Befehle implementiert.&lt;br /&gt;
&lt;br /&gt;
==== set active ====&lt;br /&gt;
Setzt das Device in den Status &#039;active&#039;.&lt;br /&gt;
&lt;br /&gt;
==== set inactive ====&lt;br /&gt;
Setzt das Device in den Status &#039;inactive&#039;, es werden keine Befehle mehr ausgeführt. Dieser Status entspricht dem Attribut &#039;disable&#039;, ist aber nicht mit dem roten Fragezeichen (fhem save) verbunden.&lt;br /&gt;
&lt;br /&gt;
==== set on/off [&amp;lt;parameter&amp;gt;]====&lt;br /&gt;
Setzt das Device in den Status &#039;on&#039; oder &#039;off&#039;. Alle Befehle der &#039;on/off-Zweige&#039; werden ausgeführt.&lt;br /&gt;
Optional kann den Befehlen &#039;on&#039; und &#039;off&#039; ein weiterer Parameter mit übergeben werden. Dieser wird im Reading &#039;Parameter&#039; hinterlegt und es kann sofort in &#039;Freecmds&#039; oder &#039;Conditions&#039; darauf zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
==== set reload_timer ====&lt;br /&gt;
Alle gesetzten Timer werden gelöscht und neu berechnet.&lt;br /&gt;
&lt;br /&gt;
==== set change_renamed &amp;lt;oldname&amp;gt; &amp;lt;newname&amp;gt; ====&lt;br /&gt;
Sollten sich Devicenammen im ausführenden Teil geändert habe (affected Devices, Conditions, etc.) so kann das MSwitch mit diesem Befehl angepasst werden, ohne alle Einstellungen neu einstellen zu müssen.&lt;br /&gt;
&lt;br /&gt;
==== set exec_cmd1 / set exec_cmd1 ID [&amp;lt;ID&amp;gt;] ====&lt;br /&gt;
Bewirkt das sofortige Ausführen des entsprechenden Befehlszweiges. Bei Angabe einer ID werden nur die Befehle mit der entsprechenden ID ausgeführt.&lt;br /&gt;
&lt;br /&gt;
==== set MSwitch_backup ====&lt;br /&gt;
Erstellt eine Backup-Datei aller MSwitch Devices unter ./fhem/MSwitch_backup.cfg.&lt;br /&gt;
&lt;br /&gt;
Daten dieser Datei können im Bedarfsfall für einzelne oder gleichzeitig alle MSwitch Devices wieder zurückgespielt (hergestellt) werden.&lt;br /&gt;
&lt;br /&gt;
==== set del_delays ====&lt;br /&gt;
Löscht alle anstehenden, verzögerten Befehle (delays).&lt;br /&gt;
&lt;br /&gt;
==== set reset_cmd_count:1,2 ====&lt;br /&gt;
Löscht das entsprechende EVT_CMD_COUNT - Reading (entspricht Rückstellung auf &#039;0&#039;).&lt;br /&gt;
&lt;br /&gt;
==== set fakeevent [&amp;lt;device&amp;gt;]:&amp;lt;reading&amp;gt;:&amp;lt;arg&amp;gt; ====&lt;br /&gt;
Beispiel: &amp;lt;device&amp;gt; fakeevent state:on&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ob der Name (&amp;lt;device&amp;gt;) angegeben werden muss, oder nicht, ist abhängig davon, ob auf ein einzelnes Device, oder GLOBAL getriggert wird. Bei GLOBALEN Triggern muss das Device mit angegeben werden. Wird auf ein Device getriggert, so wird das Device automatisch gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit diesem Befehl kann das MSwitch Device neu getriggert werden, indem hier ein Event &#039;gefaked&#039; wird. Das MSwitch Device reagiert dann so, als wäre dieses Event vom getriggerten Gerät generiert worden. &lt;br /&gt;
&lt;br /&gt;
Dieses kann nötig sein, um z.B. einen Watchdog zu realisieren, in dem es nötig ist, dass sich das MSwitch Device mit einem bestimmten Event selber neu triggert - ggf. mit einem entsprechenden Delay (affected Device muss dafür u.A. des MSwitch Device selber sein).&lt;br /&gt;
&lt;br /&gt;
Es wird hierbei KEIN echtes Event generiert welches das System beeinflusst, sondern ausschließlich ein MSwitch-Interner Befehl umgesetzt!&lt;br /&gt;
&lt;br /&gt;
Bei dem Einsatz dieser Möglichkeit sollte das Attribut &#039;MSwitch_Safemode&#039; UNBEDINGT aktiviert sein, da &#039;Experimente&#039; hier schnell in einer Endlosschleife enden können, die nur durch ein Reboot unterbrochen werden kann. &lt;br /&gt;
&lt;br /&gt;
Ggf. werde ich hier sogar eine entsprechende Änderung vornehmen, dass dieser Befehl nur zur Verfügung steht, wenn Safemode aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
=== get-Befehle ===&lt;br /&gt;
==== get show_timer [&amp;lt;show&amp;gt;&amp;lt;delete&amp;gt;] ====&lt;br /&gt;
;Show&lt;br /&gt;
:Zeigt alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren.&lt;br /&gt;
;Delete&lt;br /&gt;
:Löscht alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren. Schaltbefehle basierend auf rein zeitabhängigen Angaben werden neu berechnet und gesetzt.&lt;br /&gt;
&lt;br /&gt;
==== get restore_MSwitch_data [&amp;lt;this_device&amp;gt;&amp;lt;all_devices&amp;gt;] ====&lt;br /&gt;
;this_device&lt;br /&gt;
:Stellt die Daten des Devices aus der Backupdatei wieder her, sofern diese in der Backupdatei gefunden werden (gesucht wird hier nach dem Namen des Devices).&lt;br /&gt;
;all_devices&lt;br /&gt;
:Stellt die Daten aller MSwitch Devices wieder her, sofern diese in der Backupdatei vorhanden sind. Diese Aktion kann einige Zeit in Anspruch nehmen und wird daher im Hintergrund (nonblocking) ausgeführt. Nach Beendigung erfolgt eine Benachrichtigung.&lt;br /&gt;
&lt;br /&gt;
Die Devices sind nach einem Restore funktionsfähig. Empfohlen wird ein Neustart von FHEM.&lt;br /&gt;
&lt;br /&gt;
==== get_config ==== &lt;br /&gt;
Zeigt die Konfigurationsdatei des MSwitchdevices an; diese kann in dem Fenster editiert werden. Das sollte nur von erfahrenen Usern getan werden! Im Normalfall sollte das Device nur über die Weboberfläche konfiguriert werden und eine falsche Konfiguration kann hier zu einem FHEM Absturz führen.&lt;br /&gt;
&lt;br /&gt;
==== get_support_info ==== &lt;br /&gt;
Öffnet ein Fenster mit einer formatierten Ansicht aller Einstellungen des Devices. Bei Supportanfragen sollte dieses immer mit geposted werden.&lt;br /&gt;
&lt;br /&gt;
==== get_MSwitch_preconf ====&lt;br /&gt;
Lädt vorkonfigurierte MSwitch-Devices. Diese Option ist nur dann vorhanden, wenn das Aktualisieren dieser vorkonfigurierten Devices im FHEM Update aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
Diese kann durch ein einmaliges Update erfolgen mit:&lt;br /&gt;
:&amp;lt;code&amp;gt;update all https://raw.githubusercontent.com/Byte009/MSwitch_Addons/master/controls_mswitchaddons.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Webinterface ==&lt;br /&gt;
MSwitch wird im Wesentlichen über das Webinterface eingerichtet. Wählt man das folgende Attribut&lt;br /&gt;
:&amp;lt;code&amp;gt;attr &amp;lt;name&amp;gt; MSwitch_Help 1&amp;lt;/code&amp;gt;&lt;br /&gt;
so wird im Modul selber eine sehr umfangreiche Hilfe angezeigt. Über das gesamte Webinterface hinweg erscheinen kleine Fragezeichen, die man anklicken kann und die beschreiben, was in dem jeweiligen Textfeld sinnvollerweise einzugeben ist bzw. was das Modul an dieser Stelle erwartet.&lt;br /&gt;
&lt;br /&gt;
Das Webinterface besteht aus vier Teilen. Änderungen in jedem Abschnitt müssen in dem jeweiligen Teil bestätigt werden und auch nur diese werden gespeichert. Bevor ein weiterer Teil bearbeitet wird, sollten Änderungen gespeichert werden, sie gehen sonst verloren.&lt;br /&gt;
&lt;br /&gt;
=== Trigger device/time ===&lt;br /&gt;
==== Trigger Device ====&lt;br /&gt;
In diesem Feld wird das Device ausgewählt, dessen Events eine Aktion auslösen sollen. Dazu werden alle verfügbaren Devices in einem Dropdownfeld angeboten.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es eine Auswahl &#039;GLOBAL&#039;, wenn das Attribut &#039;MSwitch_Expert&#039; gesetzt ist. Bei Auswahl dieser Option werden &#039;&#039;&#039;alle&#039;&#039;&#039; von FHEM generierten Events durch das MSwitch Device weiterverarbeitet, eine weitere Begrenzung der aktivierenden Events kann (und sollte) dann in einem folgenden Eingabefeld erfolgen, um die Systemlast zu reduzieren.&lt;br /&gt;
&lt;br /&gt;
==== Trigger Device Global Whitelist ====&lt;br /&gt;
Dieses Feld ist nur verfügbar, wenn als Trigger &#039;GLOBAL&#039; gewählt wurde.&lt;br /&gt;
&lt;br /&gt;
Hier kann die Liste eingehender Events weiter eingeschränkt werden. Es handelt sich um eine Whitelist, d.h., wenn es keine Einträge gibt, werden Events aller Devices verarbeitet. Sobald ein oder mehrere Einträge gemacht werden, werden nur noch Events der hier benannten Devices verarbeitet. Als Angabe können hier Devices benannt werden oder ganze DeviceTypen (z.B. TYPE=FS20). Mehrere Angaben sind durch Komma zu trennen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:MSwitchWebinterface1.png|400px|thumb|right|Webinterface, oben]]&lt;br /&gt;
Im gezeigten Beispiel wurde GLOBAL gewählt, weil nicht ein einzelnes Device, sondern eine Kombination aus zwei Geräten auslösen soll. Es werden also alle Ereignisse betrachtet, wobei die Whitelist dann auf die Devices Schlafzimmer (ein Temperaturmessgerät) und Schlafzimmerfenster (ein [[HM-Sec-SCo Tür-Fensterkontakt, optisch|optischer Kontakt]]) einschränkt. &lt;br /&gt;
&lt;br /&gt;
==== Trigger time ==== &lt;br /&gt;
Es besteht die Möglichkeit, das Modul (neben den Events) zu festen Zeiten auszulösen. Dann wären in die leer stehenden Zeilen bei &amp;quot;at&amp;quot; entsprechende Termine einzutragen. Zeitangaben erfolgen durch [STUNDEN:MINUTEN|TAGE], wobei die Tage von 1-7 gezählt werden (1 steht für Montag, 7 für Sonntag usw.). &lt;br /&gt;
Mehrere Zeitvorgaben können direkt aneinandergereiht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [17:00|1][18:30|23] den Trigger montags um 17 Uhr auslösen und dienstags sowie mittwochs um 18:30 Uhr.&lt;br /&gt;
Bei [00:10*20:00-21:00] würde der Schaltbefehl von 21 Uhr bis 21 Uhr alle 10 Minuten ausgeführt. Bei [?20:00-21:00] würde der Schaltbefehl zu einem zufälligen Zeitpunkt zwischen 20 und 21 Uhr ausgeführt.  [20:00|$we] bedeutet, dass nur am Wochenende um 20:00 geschaltet wird.&lt;br /&gt;
&lt;br /&gt;
==== Trigger conditions ====&lt;br /&gt;
Hier kann die Angabe von Bedingungen erfolgen, die zusätzlich zu dem triggernden Device erfüllt sein müssen.&lt;br /&gt;
Diese Bedingungen sind eng an DOIF-Syntax angelehnt. Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich.&lt;br /&gt;
&lt;br /&gt;
Wird in diesem Feld keine Angabe gemacht, so erfolgt der Schaltvorgang nur durch das triggernde Device ohne weitere Bedingungen.&lt;br /&gt;
&lt;br /&gt;
;Zeitabhängigkeit&lt;br /&gt;
:[19:10-23:00] - Trigger des Devices erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
;Readingabhängige Trigger&lt;br /&gt;
:[Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Trigger des Device erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
:Werden Readings mit Strings abgefragt (on,off,etc.), ist statt des Gleichheitszeichens &amp;quot;=&amp;quot; der Operator &amp;quot;eq&amp;quot; zu nutzen, der String muss in Anführungszeichen &amp;quot;&amp;quot; gesetzt werden.&lt;br /&gt;
;mehrere Beispiele&lt;br /&gt;
:[19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
:[19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
:[10:00-11:00|13] - schaltet Montag und Mittwoch zwischen 10 Uhr und 11 Uhr.&lt;br /&gt;
:[{ sunset() }-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
:{ !$we } löst den Schaltvorgang nur Werktagen an aus.&lt;br /&gt;
:{ $we } löst den Schaltvorgang nur an Wochenenden, Feiertagen aus.&lt;br /&gt;
&lt;br /&gt;
Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (beispielsweise würde dann am Mittwoch noch der Schaltvorgang erfolgen, obwohl als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
Bedingungen in diesem Feld gelten nur für auslösende Trigger eines Devices und haben keinen Einfluss auf zeitgesteuerte Auslöser.&lt;br /&gt;
&lt;br /&gt;
=== Trigger details ===&lt;br /&gt;
[[Datei:MSwitchWebinterface2.png|600px|thumb|right|Webinterface, Mitte]]&lt;br /&gt;
Während im obigen Feld das Device ausgewählt  werden konnte, wird hier das Ereignis festgelegt. Das Eingabefeld besteht aus mehreren Einzelfeldern.&lt;br /&gt;
&lt;br /&gt;
Im abgebildeten Fall wird cmd1 ausgelöst, wenn der Zustand des Schlafzimmerfenster-Sensors meldet, dass das Fenster offen ist. Cmd2 wird ausgelöst, wenn die Temperatur des Schlafzimmersensors unter einen bestimmten Wert fallen wird.&lt;br /&gt;
&lt;br /&gt;
==== execute &#039;cmd1/cmd2&#039;  ====&lt;br /&gt;
Hier kann  aus einer vorbelegten Dropdownliste ausgewählt werden, welches ankommende Event den entsprechenden Befehlszweig auslösen soll. In dieser Liste werden bei entsprechender Einstellung alle ankommenden Events eines vorher definierten Devices gespeichert. In einem weiteren Feld (siehe unten) können Events manuell zugefügt werden.&lt;br /&gt;
&lt;br /&gt;
==== Save incomming events ====&lt;br /&gt;
Bei Aktivierung dieser Option werden alle ankommenden Events des oben definierten Devices (oder Global) gespeichert und in entsprechenden Dropdownlisten angeboten.&lt;br /&gt;
&lt;br /&gt;
Da hier doch erhebliche Datenmengen anfallen können (je nach Device) wird empfohlen, diese Option nach der Konfiguration des Devices zu deaktivieren.&lt;br /&gt;
&lt;br /&gt;
==== add event ====&lt;br /&gt;
Hier besteht die Möglichkeit, unabhängig von der Option, ankommende Events automatisch zu speichern. Manuell Events anzulegen, die in den Dropdownliste zur Auswahl angeboten werden, ohne das entsprechendes Event erst vom Device geliefert werden muss.&lt;br /&gt;
&lt;br /&gt;
Es können mehrere Events gleichzeitig eingegeben werden, eine Trennung erfolgt durch &amp;quot; , &amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Hier ist zu unterscheiden, ob das gewählte triggernde Device ein einfaches Device ist oder ob der Trigger &#039;GLOBAL&#039; ist.&lt;br /&gt;
Bei triggernden Devices können Events in folgendem Formaten zugefügt werden:&lt;br /&gt;
&lt;br /&gt;
- *                                                    - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:wert   (z.b. state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:*      (z.b. state:* )                       - Aktion erfolgt auf die Events &amp;quot;state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:(wert1/wert2/wert3) (z.b. state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;state:left&amp;quot; oder &amp;quot;state:right&amp;quot; etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Falls auf &#039;GLOBALE&#039; Events getriggert wird, muss das auslösende Device vorangestellt werden:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
- *                                                           - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:wert   (z.b. device:state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;device:state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:*      (z.b. device:state:* )                       - Aktion erfolgt auf die Events &amp;quot;device:state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:(wert1/wert2/wert3) (z.b. device:state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;device:state:left&amp;quot; oder &amp;quot;devicestate:right&amp;quot; etc.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Device kann auch hier gegen &amp;quot;*&amp;quot; ersetzt werden (*:state:on). In diesem Fall erfolgt eine Aktion auf alle Events die z.B. &amp;quot;state:on&amp;quot; enthalten, egal welches Device triggert.&lt;br /&gt;
&lt;br /&gt;
==== test event ====&lt;br /&gt;
Dieses Feld wird angeboten, wenn entsprechende vom Triggerdevice gelieferte Events gespeichert wurden.&lt;br /&gt;
&lt;br /&gt;
Durch Auslösen dieser Funktion wird das Event simuliert und entsprechende definierte Aktionen ausgelöst. Diese Funktion dient ausschließlich zum Testen der eingestellten Konfiguration. Alle entsprechenden Befehle werden ausgeführt, als würde das Event real eintreffen.&lt;br /&gt;
&lt;br /&gt;
==== apply filter to saved events ====&lt;br /&gt;
Beschreibung folgt&lt;br /&gt;
&lt;br /&gt;
==== clear saved event ====&lt;br /&gt;
Es werden alle gespeicherten Events gelöscht.&lt;br /&gt;
&lt;br /&gt;
Ausnahme: Events, die als Trigger eingestellt sind, bleiben erhalten.&lt;br /&gt;
&lt;br /&gt;
=== Affected devices ===&lt;br /&gt;
[[Datei:MSwitch_Screen_5.png|mini|rechts|affected devices]]&lt;br /&gt;
Dieser Abschnitt beinhaltet die Auswahl der Devices, die auf ein Event reagieren sollen.&lt;br /&gt;
&lt;br /&gt;
In dem Auswahlfeld werden alle Devices angeboten, die eines der folgenden Kriterien erfüllen:&lt;br /&gt;
# Die Abfrage &amp;quot;set Device ?&amp;quot; liefert einen Befehlssatz&lt;br /&gt;
# Das Attribut &#039;webcmd&#039; des Devices enthält Einträge&lt;br /&gt;
# Das Attribut &#039;MSwitch_Activate_MSwitchcmds&#039; ist aktiviert und das Attribut &#039;MSwitchcmds&#039; des betreffenden Devices enthält einen Befehlssatz&lt;br /&gt;
&lt;br /&gt;
Einzige Ausnahme ist der erste Listeneintrag &#039;FreeCMD&#039;. Die Auswahl dieses Eintrages bietet später die Möglichkeit Befehle auszuführen, die nicht an ein Device gebunden sind. Der Code in einem FreeCmd kann entweder reiner FHEM-Code sein ( set device on ) oder reiner Perl-Code. Wenn es sich um reinen Perl-Code handelt, ist dieser in geschweifte Klammen zu setzen { Perl-Code }.&lt;br /&gt;
&lt;br /&gt;
=== Device actions ===&lt;br /&gt;
[[Datei:Webinterface3.png|mini|rechts|device_actions]]&lt;br /&gt;
Hier stellt man die auszuführenden Aktionen der eingestellten Devices ein. Im ersten Abschnitt oben befindet sich ein FreeCmd, mit dem beliebige Kommandos eingetragen werden können. Im abgebildeten Beispiel ist dies sogar selbst definierter Perl-Code (die Funktion DebianMail sendet eine Mail). &lt;br /&gt;
&lt;br /&gt;
==== MSwitch cmd1/cmd2:  ====&lt;br /&gt;
Man wählt den Befehl aus dem betreffenden Device aus. Bei freien Textfeldern (wie im Fall des FreeCmd) wird der Befehl eingegeben.&lt;br /&gt;
&lt;br /&gt;
Es werden alle verfügbaren Befehle des Devices zur Auswahl angeboten. Je nach Attribut-Einstellungen werden Einträge aus entsprechenden &#039;webcmds&amp;quot; oder &#039;MSwitchcmds&#039; einbezogen. In Abhängigkeit des Befehls stehen unter Umständen weitere Felder oder Widgets zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
05.04.2018 NEU: Auswahlfeld &#039;MSwitchtoggle&#039; -&amp;gt; Beschreibung wird noch ergänzt !&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 condition  ====&lt;br /&gt;
Mit diesem Feld kann die Ausführung des Befehls von weiteren Bedingungen abhängig gemacht werden. Bei der Abfrage von Readings nach Strings (on, off, etc.) ist statt &amp;quot;=&amp;quot; &amp;quot;eq&amp;quot; zu nutzen und der String muss in &amp;quot;x&amp;quot; gesetzt werden. Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
#Zeitabhängiges schalten: [19:10-23:00] - Schaltbefehl erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
#Readingabhängiges schalten [Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Schaltbefehl erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
&lt;br /&gt;
Soll nur an bestimmten Wochentagen geschaltet werden, muss eine Zeitangabe gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [10:00-11:00|13] den Schaltvorgang nur Montag und Mittwoch zwischen 10 Uhr und 11 Uhr auslösen. Hierbei zählen die Wochentage von 1-7 für Montag-Sonntag.&lt;br /&gt;
&lt;br /&gt;
Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich:&lt;br /&gt;
* [19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
* [19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
* [{sunset()}-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
* { !$we } löst den Schaltvorgang nur Werktagen aus&lt;br /&gt;
* { $we } löst den Schaltvorgang nur Wochenenden, Feiertagen aus&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung:&#039;&#039;&#039; Bei Anwendung der geschweiften Klammern zur Einleitung eines Perl Ausdrucks ist unbedingt auf die Leerzeichen hinter und vor der Klammer zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (zum Beispiel würde auch am Mittwoch noch der Schaltvorgang erfolgen, wenn als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
; $EVENT:&lt;br /&gt;
: Die Variable EVENT enthält den auslösenden Trigger, d.h. es kann eine Reaktion in direkter Abhängigkeit zum auslösenden Trigger erfolgen.&lt;br /&gt;
&lt;br /&gt;
[$EVENT] eq &amp;quot;state:on&amp;quot; würde den Kommandozweig nur dann ausführen, wenn der auslösende Trigger &amp;quot;state:on&amp;quot; war. Wichtig ist dieses, wenn bei den Triggerdetails nicht schon auf ein bestimmtes Event getriggert wird, sondern hier durch die Nutzung eines Wildcards (*) auf alle Events getriggert wird, oder auf alle Events eines Readings z.B. (state:*).&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 delay  ====&lt;br /&gt;
Ein Eintrag in diesem Feld führt zur verzögerten Ausführung des Befehls nach Eintreffen des Events. Dabei kann der Befehl ohne weitere Prüfung der Bedingung ausgelöst werden. Es ist aber auch möglich, dass die Bedingung bei Ausführung erneut geprüft wird. Die Zeitangabe muss im Format hh:mm:ss vorliegen.&lt;br /&gt;
&lt;br /&gt;
Statt einer unmittelbaren Zeitangabe kann hier auch ein Verweis auf ein Reading eines Devices erfolgen :&amp;lt;br&amp;gt;&lt;br /&gt;
[NAME.reading] des Devices -&amp;gt;z.B. [dummy.state]&lt;br /&gt;
&lt;br /&gt;
==== add action  ====&lt;br /&gt;
Mit diesem Button kann ein weiteres Eingabefeld für das entsprechende Device angelegt werden, um z.B. einen weiteren Befehl (ggf.) zeitverzögert auszuführen.&lt;br /&gt;
&lt;br /&gt;
==== delete this action  ====&lt;br /&gt;
Mit diesem Button wird der entsprechende Befehl für das Device gelöscht.&lt;br /&gt;
&lt;br /&gt;
==== check condition  ====&lt;br /&gt;
[[Datei:MSwitch_Screen_7.png|mini|rechts|check]]&lt;br /&gt;
Die angegebenen &#039;conditions&#039; werden in Zusammenhang mit ggf. ausgewählten Devices auf Syntax und Ergebnis geprüft. Es erfolgt eine Ausgabe des Prüfungsergebnisses.&lt;br /&gt;
&lt;br /&gt;
==== Repeat und Repeatdelay ====&lt;br /&gt;
Man kann mehrfache Wiederholungen erzwingen. Repeat gibt dabei an, wie oft das Kommando wiederholt wird (Anzahl). Repeatdelay gibt an, wie viel Sekunden zwischen einzelnen Wiederholungen liegen sollen.&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Folgende Attribute stehen zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Debug (0:1:2:3:4) ===&lt;br /&gt;
0 - Abgeschaltet&amp;lt;br&amp;gt;&lt;br /&gt;
1 - Schaltet Felder zum testen der Conditionstrings etc. an&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Alle ausgehenden Befehle werden nur simuliert und nicht ausgeführt. Es erfolgt eine Protokollierung in einer separaten Datei. Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Es erfolgt eine Protokollierung in einer separaten Datei. Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
4 - erweiterte Debug-Funktion (nur für Entwicklung - wechselnde Funktion )&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Expert (0:1) ===&lt;br /&gt;
In der Liste der möglichen Trigger erscheint das Selectfeld &#039;GLOBAL&#039;. Dieses ermöglicht das Setzen eines Triggers auf alle Events und damit nicht nur auf einzelne Devices. In einem weiteren Feld kann eine weitere Selektion der triggernden Events erfolgen.&lt;br /&gt;
&lt;br /&gt;
Es stehen weitere Felder &#039;Repeats&#039; und &#039;Repeatdelay in sec&#039; zur Verfügung. Eine hier getätigte Einstellung bewirkt X-fache Wiederholung von gesetzten Befehlen im Abstand der gesetzten Sekunden.&lt;br /&gt;
&lt;br /&gt;
Weiterhin kann über das Auswahlfeld &#039;priotity&#039; bei jedem &#039;affectes device&#039; die Reihenfolge beim abarbeiten der Befehle beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequenz &amp;lt;Suchmuster&amp;gt; ===&lt;br /&gt;
In diesem Attribut können ein oder mehrere Suchmuster angegeben werden ,die eine Schaltsequenz darstellen und vom Device erkannt werden.&lt;br /&gt;
&lt;br /&gt;
Die Angabe muss folgende Syntax haben:&lt;br /&gt;
:&amp;lt;code&amp;gt;Device1:reading1:event1 Device1:reading1:event1-2 Device1:reading1:event1-3/..../....&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mehrere Suchmuster müssen durch &amp;quot;/&amp;quot; getrennt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
:&amp;lt;code&amp;gt;Dummy:state:on Dummy:state:off Dummy:state:on&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erkennt das Device dieses Suchmuster in den Schaltvorgängen des Devices (Dummy), wird das Reading &amp;quot;SEQUENCE&amp;quot; auf &amp;quot;match&amp;quot; gesetzt, das Reading &amp;quot;SEQUENCE_NUMBER&amp;quot; auf die Nummer der gefundenen Sequenz, wenn es mehrere Suchmuster gibt. Beide Readings können in den &amp;quot;Conditions&amp;quot; eines Schaltbefehles abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequence_time &amp;lt;Zeit in Sekunden&amp;gt; ===&lt;br /&gt;
Beinhaltet die Zeit in Sekunden, die es dauern darf, um eine Sequenz vollständig auszuführen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Extensions (0:1) ===&lt;br /&gt;
Es wird eine zusätzliche Schaltoption &#039;MSwitchToggle&#039; in den Geräten angeboten. Diese kann genutzt werden, wenn zuschaltende Geräte eine Togglefunktion nicht von Haus aus anbieten.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe muss in folgendem Format gemacht werden:&lt;br /&gt;
:&amp;lt;code&amp;gt;on/off/state/suchmuster1/suchmuster2&amp;lt;/code&amp;gt;, wobei die letzten drei Angaben optional sind.&lt;br /&gt;
&lt;br /&gt;
Funktion: Bei Ausführung des Befehls wird das Gerät &#039;on&#039; oder &#039;off&#039; geschaltet (on/off), Voraussetzung ist, dass der &#039;state&#039; dieses Gerätes auch den &#039;state on&#039; oder &#039;off&#039; annimmt. Sollte dieses nicht der Fall sein, so kann mit dem Feld &#039;state&#039; angegeben werden, in welchem Reading der aktuelle Status vorkommt und wie dieser lautet (suchmuster1/suchmuster2). Dieses &#039;state&#039; kann mehrere Angaben enthalten, das Vorkommen der Suchmuster ist aber Voraussetzung.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Delete_Delays (0:1) ===&lt;br /&gt;
Bewirkt das Löschen aller anstehende Timer (Delays) bei dem Auftreten eines erneuten, passenden Events. Bei der Option &#039;0&#039; bleiben bereits gesetzte Delays aus einem vorherigen, getriggertem Event erhalten und werden ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1)&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Devicecmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz liefern (bei Abfrage set DEVICE ?).&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Webcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut Webcmd hinterlegt haben. Die in Webcmd hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten.&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Activate_MSwitchcmds (0:1) ===&lt;br /&gt;
Fügt jedem vorhandenen Device as Attribut &#039;MSwitchcmd&#039; hinzu.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_MSwitchcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut MSwitchcmds hinterlegt haben. Die in MSwitchcmds hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten. Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr Angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Lock_Quickedit (0:1) ===&lt;br /&gt;
Voreinstellung für die Auswahlliste &#039;Affected Devices&#039;. Bei der Option (1) ist diese voreingestellt gesperrt und kann nur über einen zusätzlichen Button geändert werden. Da es sich hier um ein Feld mit der Möglichkeit einer Mehrfacheingabe handelt handelt ist die Voreinstellung 1, um versehentliche nicht gewünschte Änderungen zu vermeiden (Auswahl einer Option ohne &#039;Strg&#039; bewirkt das löschen aller bereits gesetzten Optionen).&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay (0:10:20:30:60) ===&lt;br /&gt;
Diese Einstellung beeinflusst den Start von MSwitch nach einem FHEM Start. MSwitch ignoriert für die angegebene Zeit in Sekunden alle eingehenden Events um u.a. Startverzögerungen zu vermeiden. Bei nicht gesetztem Attribut gilt hier eine Zeit von 30 Sekunden. Diese sollte auch nur in Ausnahmefällen bzw. bei besonderem Bedarf geändert werden.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (30).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Ignore_Types ===&lt;br /&gt;
Beinhaltet eine Liste von Device&#039;&#039;typen&#039;&#039;, die in den Auswahllisten &#039;&#039;nicht&#039;&#039; dargestellt werden. Hier ist es sinnvoll, Devicetypen einzutragen, die in aller Regel nicht geschaltet werden oder nicht geschaltet werden können, um die Auswahllisten übersichtlicher zu halten. Einzelne Devicetypen sind durch Leerzeichen zu trennen.&lt;br /&gt;
&lt;br /&gt;
Voreinstellung: notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe kann hier in 2 Arten getätigt werden:&lt;br /&gt;
# eine Liste von devicetypen.&lt;br /&gt;
# Angabe einer devspec z.B. &amp;quot;TYPE=watchdog&amp;quot;. Hier ist zu beachten, dass in diesem Fall alle Geräte in die Ignoreliste einbezogen werden, die NICHT der devspec entsprechen. Weiterhin muss die devspec in Anführungszeichen gesetzt werden!&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Trigger_Filter ===&lt;br /&gt;
Beinhaltet eine Liste von Events, die bei eingehenden Events unberücksichtigt bleiben. Diese werde dann auch nicht gespeichert.&lt;br /&gt;
&lt;br /&gt;
Hier kann mit Wildcards (*) gearbeitet werden. Einzelne Events sind durch Komma &#039;,&#039; zu trennen.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (keine).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Wait (sec)===&lt;br /&gt;
Bei gesetztem Attribut (Zeit in Sekunden) nimmt Das MSwitch Device für den eingestellten Zeitraum keine Befehle mehr entgegen und ignoriert eingehende Events&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Event_Id_Distributor ===&lt;br /&gt;
Dieses Attribut hat nur dann eine Funktion, wenn auch das Attribut &#039;MSwitchExpert&#039; auf &#039;1&#039; gesetzt ist.&lt;br /&gt;
Hier können verschiedene auslösende Events auf Aktionen mit angegebenen IDs umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Sollte bei den &#039;trigger details :&#039; in einem Zweig ( cmd1 ) z.B. auf mehrere Events getriggert werden ( regex z.B. state:(on|off) ) so werden für beide Events jeweils der Zweig &#039;cmd1&#039; - alle  Aktionen ohneID - ausgeführt. Durch entsprechende Einträge kann für entsprechende Events auf eine Aktion umgeleitet werden, für die eine ID definiert ist. Die Syntax lautet:&lt;br /&gt;
:&amp;lt;code&amp;gt;state:on=&amp;gt;cmd1 ID 1,2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden bei auslösendem Event &#039;state:on&#039; nur die Aktionen aus cmd1 mit den IDs 1 und 2 ausgeführt. Mehrere Angaben sind durch new Line zu trennen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Selftrigger_always (0,1)===&lt;br /&gt;
(dieses Attribut steht ab Modulversion 2.5 zur Verfügung)&lt;br /&gt;
&lt;br /&gt;
Die Aktivierung dieses Attributes (1) bewirkt, dass alle SET Aktionen des Devices einen (internen) Event auslösen, auf die das Device selber reagiert. Diese Option kann zusätzlich zu einem vorhandenen Trigger aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Diese Events sind lediglich Device intern, d.h es werden keine Modulübergreifenden Events ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Auftretende und auswertbare interne Events haben immer folgendes Format und können darüber ausgewertet werden.&lt;br /&gt;
&lt;br /&gt;
MSwitch_Self:aktion:wert &lt;br /&gt;
MSwitch_Self:pct:100&lt;br /&gt;
&lt;br /&gt;
Es werden nur interne Events für set-Aktionen ausgelöst, die im Attribut setlist hinterlegt sind.&lt;br /&gt;
&lt;br /&gt;
Als weitere Besonderheit unterliegen diese internen Events nicht dem &#039;wait&#039; Befehl/Attribut.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Mode (Notify,Full,Toggle,Dummy)===&lt;br /&gt;
Schaltet das Modul zwischen verschiedenen Modi um, mit entsprechend angepasster Weboberfläche.&lt;br /&gt;
&lt;br /&gt;
==== Notify ====&lt;br /&gt;
Das Device kann nicht manuell umgeschaltet werden. Es gibt nur zwei ausführbare Zweige (execute &#039;cmd1&#039; commands und execute &#039;cmd2&#039; commands). Der Status des Devices wird nicht als &#039;on&#039; oder &#039;off&#039; angezeigt, sondern lediglich als &#039;active&#039;&lt;br /&gt;
&lt;br /&gt;
Dieser Mode ist am ehesten mit einem Notify zu Vergleichen.&lt;br /&gt;
&lt;br /&gt;
==== Full ====&lt;br /&gt;
Es stehen alle Funktionen zur Verfügung.&lt;br /&gt;
==== Toggle ====&lt;br /&gt;
Sehr vereinfachter Mode. Es stehen keine verschiedenen Zweige zur Verfügung. Hier ist das Device manuell schaltbar und wird bei jedem definierten Event &#039;Umgeschaltet&#039;, entsprechend definierte Befehle für &#039;cmd1&#039; oder &#039;cmd2&#039; werden ausgeführt.&lt;br /&gt;
==== Dummy====&lt;br /&gt;
ACHTUNG: Funktionsänderung mit V2.61&lt;br /&gt;
&lt;br /&gt;
Der Mode &#039;Dummy&#039; ist ein eingeschränkter Modus. &lt;br /&gt;
Dieser bietet die Funktionalität eines Dummys kombiniert mit der Funktionalität eines Notifys und kann somit die gerne genutzte Kombination Dummy-Notify gegen ein Device ersetzen.&lt;br /&gt;
&lt;br /&gt;
Achtung: Devices die einmal in dem Modus &#039;Dummy&#039; gesetzt wurden können nicht wieder in einen anderen Mode geschaltet werden ! &lt;br /&gt;
&lt;br /&gt;
Der Dummy-Mode kann nur in einem neu angelegtem, leeren MSwitch aktiviert werden. Sobald ein angelegtes MSwitch einmal verändert wurde (modify trigger etc.) ist ein Umschalten nicht mehr möglich und die Option nicht mehr verfügbar.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Condition_Time (0,1)===&lt;br /&gt;
In der Grundeinstellung (0) werden für das zeitgesteuerte Schalten keine definierten Conditionen im Feld &#039;Trigger condition&#039; überprüft, sondern die Schaltbefehle werden in jedem Fall ausgeführt. Mit der Einstellung (1) wird diese Überprüfung auch für zeitgesteuerte Befehle zugeschaltet.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Time (HH:MM:SS-HH:MM:SS)===&lt;br /&gt;
Bei Aktivierung wird vor jedem Ausführen eines verzögerten Befehls ( Delay ) eine Zufallszeit generiert, die im Rahme der hier angegebenen Zeitspanne liegt. Auf diese Zufallszahl kann in den Delays zugegriffen werden, durch die Angabe &#039;[random]&#039; statt einer direkten Zeitangabe. Bei nicht gesetztem Attribut ergibt die Angabe von &#039; [random] &#039; hier immer &#039;00:00:00&#039;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Number ===&lt;br /&gt;
Bei Aktivierung dieses Attributes (der Inhalt kann einen beliebige Zahl sein) werden vom Device 2 Readings angelegt (Device:RandomNr) und (Device:RandomNr1). RandomNr wird vor jedem Ausführen eines Befehls aktualisiert und neu generiert, d.h wenn ein MSwitch Device mehrere Geräte schaltet, wird (auch in einem Durchgang) vor jedem Befehl dieses Reading neu gesetzt. RandomNr1 wird lediglich bei Ausführung des MSwitch Devices einmal neu gesetzt, d.h. nicht vor jedem Befehl der ausgeführt wird.&lt;br /&gt;
Die Readings werden mit einer Zufallszahl zwischen 0 und dem hier eingestellten Wert gesetzt.&lt;br /&gt;
&lt;br /&gt;
Auf diese Readings kann in jeder Condition mit z.B. &#039;[$NAME:ReadingNr1] = 1&#039; zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
D.h., das in der Condition angegebene Reading ( [$NAME:ReadingNr1] ) muss in diesem Fall den Wert 1 angenommen haben, ansonsten wird der Befehl nicht ausgeführt. &lt;br /&gt;
Der Befehl wird somit nur mit einer Wahrscheinlichkeit von 1 zu ( gesetzter Wert im Attr. ) ausgeführt.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Reset_EVT_CMD1(2)_COUNT ===&lt;br /&gt;
Bei Aktivierung dieses Attributes steht in den Readings das Reading &#039;EVT_CMD1_COUNT&#039; bzw. &#039;EVT_CMD2_COUNT&#039; zur Verfügung. Dieses kann in den Conditions genutzt werden, um z.B. nur bei jedem x-ten Eintreffen eines auslösenden Events einen Befehl auszuführen. Bei jedem Eintreffen eines gültigen Events werden die Zähler um 1 erhöht (für den jeweiligen Zweig). &lt;br /&gt;
Ist hier der Wert &#039;0&#039; eingetragen, wird der Zähler fortlaufend (endlos) erhöht. Wird ein Wert größer 0 eingetragen, wird der Zähler mit Erreichen dieses Wertes automatisch wieder auf Null gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit Löschen dieses Attributes werden die entsprechenden Readings ebenfalls gelöscht.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Safemode (0:1)===&lt;br /&gt;
Bietet einen (gewissen) Schutz vor falschen Konfigurationen und somit entstehenden Endlosschleifen.&lt;br /&gt;
Bei aktiviertem Attribut (1) erkennt das Modul Endlosschleifen eines Devices und beendet diese.&lt;br /&gt;
&lt;br /&gt;
In diesem Fall erfolgt ein Logeintrag und das Device wird per Attribut auf &#039;Disabled&#039; gesetzt.&lt;br /&gt;
Es wird ein letztes Event generiert, auf das reagiert werden kann:&lt;br /&gt;
:&amp;lt;code&amp;gt;2018-05-31 09:39:21 MSwitch &amp;lt;NAME&amp;gt; Safemode: on&amp;lt;/code&amp;gt;&lt;br /&gt;
Im Webinterface erfolgt bei betroffenem Device ein entsprechender Hinweis.&lt;br /&gt;
&lt;br /&gt;
In der Grundkonfiguration ist dieses Attribut nicht gesetzt, es empfiehlt sich aber, bei neuen (komplizierten) Devices, dieses - zumindest anfänglich - zu aktivieren.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Read_Log(0:1)===&lt;br /&gt;
Ermöglicht den Zugriff auf das Logfile als Trigger.&lt;br /&gt;
&lt;br /&gt;
Hier gibt es mehrere Konfigurationsmöglichkeiten:&lt;br /&gt;
* Bei aktiviertem Attribut enthält die Auswahl des Triggerdevices die Option &#039;LOGFILE&#039;. Bei dieser Auswahl werde alle Logeinträge erkannt und in ein internes Event umgewandelt, auf das regiert werden kann.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl &#039;GLOBAL&#039; im &#039;Trigger_Device&#039; wird auf ALLE Events und alle Logeinträge reagiert.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl eines bestimmten Devices im &#039;Trigger_Device&#039; wird auf alle Events  und auf alle Logeinträge des gewählten Devices reagiert. Hier ist zu beachten, dass FHEM mir keine Möglichkeit bietet, wirklich herauszufinden, welches Device denn nun einen Logeintrag generiert hat. D.h., dieses wird vom Vorhandensein des Namens im Logeintrag abhängig gemacht und MSwitch reagiert nur dann auf einen Logeintrag, wenn der Name des Devices in diesem Eintrag vorhanden ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Help(0:1)===&lt;br /&gt;
Schaltet Hilfebuttons zu den einzelnen Eingabefeldern an oder aus.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Comments(0:1)===&lt;br /&gt;
Schaltet Kommentarfelder zu den einzelnen &#039;affected_devices an.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_generate_Events(0:1)===&lt;br /&gt;
Reduziert bei Einstellung &#039;1&#039; die vom MSwitch-Devices erzeugten Events auf ein absolutes Minimum. Insbesondere bei Verwendung von &#039;MSwitch_Read_Log&#039; zu empfehlen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay ===&lt;br /&gt;
Bestimmt die Verzögerungszeit des MSwitches nach FHEM-Start in Sekunden. In diesem Zeitraum reagiert das Device nicht auf Events. Die Vorgabe ist hier zehn Sekunden. Diese wird auch dann angenommen, wenn das Attribut nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Inforoom ===&lt;br /&gt;
Mit diesem Attribut wird die Raumansicht eines mit dem Attribut bestimmten Raumes verändert. Dadurch sollen die wichtigsten Informationen aller MSwitch-Devices auf eine Seite dargestellt werden. Zur Nutzung sollten alle MSwitch-Devices (zusätzlich) in einen Raum sortiert werden und dieser Raum im Attribut eingestellt werden.&lt;br /&gt;
&lt;br /&gt;
Wichtig: Eine Änderung dieses Attributes bewirkt immer eine Änderung dieses Attributes in &#039;&#039;allen&#039;&#039; MSwitch devices: Es muss nur in einem Device gesetzt oder gelöscht werden um alle Devices zu erfassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
MSwitch_Screen_1.png|Raumansicht des Raumes MSwitch mit gesetztem Attribut &#039;MSwitch&#039;&lt;br /&gt;
MSwitch_Screen_2.png|Raumansicht des Raumes MSwitch ohne gesetztes Attribut&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es werden folgende Informationen bereitgestellt:&lt;br /&gt;
* Infobutton zeigt den im Device gespeicherten Textes des Attributes &#039;comment&#039;&lt;br /&gt;
* Device und Events, die das Device triggern&lt;br /&gt;
* Zeiten, zu denen verschiedene Zweige des Devices ausgeführt werden&lt;br /&gt;
* Devices, die durch das MSwitch Device geschaltet werden&lt;br /&gt;
* State des Devices&lt;br /&gt;
&lt;br /&gt;
== Integrierte Funktionen ==&lt;br /&gt;
&lt;br /&gt;
=== Average ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
=== Tendency ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[TEND&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;Mindestwert&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[TEND2:countdown] &amp;gt; 2&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Es wird jeweils der Durchschnitt von 2 Wertepaaren gebildet. In diesem Fall werden die letzten 4 Werte herangezogen.&amp;lt;br&amp;gt;&lt;br /&gt;
Paar 1 = Aktueller und letzter Wert, Paar 2 = Die 2 vorherigen Werte.&amp;lt;br&amp;gt;&lt;br /&gt;
Bei TEND3 werden die letzten 6 Werte zur Paarbildung genutzt.&lt;br /&gt;
&lt;br /&gt;
Mindestwert:&lt;br /&gt;
Der Wertunterschied zwischen den Wertepaaren, der minimal erreicht sein muss, um eine Tendenz zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Rechenzeichen (&amp;gt;&amp;lt;):&lt;br /&gt;
Dieses ist hier nicht als Rechenzeichen zu werten, sonder als Tendenz-Anzeige. ( &amp;lt; es wird nach fallender Tendenz gesucht / &amp;gt; sucht nach steigender Tendenz).&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolgt einmalig bei Erkennung der gesuchten Tendenz.&lt;br /&gt;
Danach erfolgt keine Schaltung mehr, solange bis eine Tendenz-Umkehr erfolgt ist.&lt;br /&gt;
Erst dann erfolgt wieder eine Schaltung bei erneuter Tendenz-Umkehr in gesuchte Richtung.&lt;br /&gt;
&lt;br /&gt;
=== Difference ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[DIFF&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;differenz&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[DIFF2:countdown] &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Gespeicherter Wert (in diesem Fall der vorletzte).&lt;br /&gt;
&lt;br /&gt;
Differenz:&lt;br /&gt;
Geforderter Differenz zwischen aktuellem und vorletztem Wert.&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolg wenn diese Bedingung &#039;wahr&#039; ist.&lt;br /&gt;
&lt;br /&gt;
Folgende Readings werden zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
DIFFERENCE (true/false) - Schaltbedingung erkannt ja/nein&lt;br /&gt;
&lt;br /&gt;
DIFFDIRECTION (up/down) - Richtung der erkannten Bedingung (steigend/fallend)&lt;br /&gt;
&lt;br /&gt;
=== Increase ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
== Tipps, Tricks, Kurzbeispiele ==&lt;br /&gt;
Wird stetig ergänzt.&lt;br /&gt;
&lt;br /&gt;
=== Blinken - Falls nicht im Device vorhanden ===&lt;br /&gt;
[[Datei:MSwitch MSwitchblink.png|center|704px]]&lt;br /&gt;
&amp;lt;br clear=all&amp;gt;&lt;br /&gt;
Lässt ein beliebiges Device 5 mal togglen, mit einem Intervall von 0.5 Sekunden (Blinkzeit somit 2,5 Sekunden)&amp;lt;br&amp;gt;&lt;br /&gt;
Die MSwitchtoggle-Funktion muss per ATTR aktiviert werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Die Repeatfunktion ist nur im Expertmode verfügbar, auch per ATTR einstellbar.&lt;br /&gt;
&lt;br /&gt;
=== Linearschalter ===&lt;br /&gt;
Umsetzung eines Linearschalters mit MSwitch.&lt;br /&gt;
&lt;br /&gt;
Eingang: Beliebiges Reading als numerischer Wert.&lt;br /&gt;
&lt;br /&gt;
Ausgang: Wird entsprechend Linear / oder umgekehrt Linear zum Eingang geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgend die Rawdefinition des MSwitchdevices und zweier Dummys (selbsterklärend)&lt;br /&gt;
&lt;br /&gt;
Alle Devices werden im Raum Lineartest angelegt, die Dummy müssen zuerst angelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod linearausgang dummy&lt;br /&gt;
attr linearausgang room Lineartest&lt;br /&gt;
attr linearausgang setList state:slider,0,1,100&lt;br /&gt;
attr linearausgang webCmd state&lt;br /&gt;
setstate linearausgang state 57&lt;br /&gt;
setstate linearausgang 2018-06-06 18:06:12 state state 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod lineareingang dummy&lt;br /&gt;
attr lineareingang room Lineartest&lt;br /&gt;
attr lineareingang setList state:slider,0,1,15000&lt;br /&gt;
attr lineareingang webCmd state&lt;br /&gt;
setstate lineareingang 6422&lt;br /&gt;
setstate lineareingang 2018-06-06 18:06:12 state 6422&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod Linearschalter MSwitch lineareingang  # linearausgang FreeCmd&lt;br /&gt;
attr Linearschalter MSwitch_Debug 0&lt;br /&gt;
attr Linearschalter MSwitch_Delete_Delays 1&lt;br /&gt;
attr Linearschalter MSwitch_Expert 0&lt;br /&gt;
attr Linearschalter MSwitch_Extensions 0&lt;br /&gt;
attr Linearschalter MSwitch_Help 0&lt;br /&gt;
attr Linearschalter MSwitch_Ignore_Types notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
attr Linearschalter MSwitch_Include_Devicecmds 1&lt;br /&gt;
attr Linearschalter MSwitch_Include_MSwitchcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Include_Webcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Inforoom MSwitch&lt;br /&gt;
attr Linearschalter MSwitch_Lock_Quickedit 1&lt;br /&gt;
attr Linearschalter MSwitch_Mode Notify&lt;br /&gt;
attr Linearschalter room Lineartest&lt;br /&gt;
&lt;br /&gt;
setstate Linearschalter active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:03:50 .Device_Affected FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:04:35 .Device_Affected_Details FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 );;my $emin=0;;my $emax=15000;;my $amin=100;;my $amax=0;;$eingang = $emin if $eingang &amp;lt; $emin;;$eingang = $emax if $eingang &amp;gt; $emax;;my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin;;readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 );;},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter:to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 .Device_Events no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .First_init done&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_on *&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_condition &lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_on no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_time &lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .V_Check V 0.3&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVENT state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTFULL lineareingang:state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART1 lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART2 state&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART3  6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 Exec_cmd set linearausgang state [Linearschalter:to_set]&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 Trigger_device lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 Trigger_log off&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 last_event state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:39:56 state active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 to_set 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
MSwitch -Configfile (bei Bedarf)&lt;br /&gt;
&amp;lt;pre&amp;gt;#V V1.54&lt;br /&gt;
#S .Device_Affected -&amp;gt; FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
#S .Device_Affected_Details -&amp;gt; FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 )[S]my $emin=0[S]my $emax=15000[S]my $amin=100[S]my $amax=0[S]$eingang = $emin if $eingang &amp;lt; $emin[S]$eingang = $emax if $eingang &amp;gt; $emax[S]my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin[S]readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 )[S]},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter.to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
#S .Device_Events -&amp;gt; no_trigger&lt;br /&gt;
#S .First_init -&amp;gt; done&lt;br /&gt;
#S .Trigger_Whitelist -&amp;gt; undef&lt;br /&gt;
#S .Trigger_cmd_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_cmd_on -&amp;gt; *&lt;br /&gt;
#S .Trigger_condition -&amp;gt; &lt;br /&gt;
#S .Trigger_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_on -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_time -&amp;gt; &lt;br /&gt;
#S .V_Check -&amp;gt; V 0.3&lt;br /&gt;
#S Trigger_device -&amp;gt; lineareingang&lt;br /&gt;
#S Trigger_log -&amp;gt; off&lt;br /&gt;
#S last_event -&amp;gt; state: 6422&lt;br /&gt;
#S state -&amp;gt; active&lt;br /&gt;
#A MSwitch_Ignore_Types -&amp;gt; notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
#A MSwitch_Include_MSwitchcmds -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Debug -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Help -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Devicecmds -&amp;gt; 1&lt;br /&gt;
#A MSwitch_Extensions -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Webcmds -&amp;gt; 0&lt;br /&gt;
#A room -&amp;gt; Lineartest&lt;br /&gt;
#A MSwitch_Inforoom -&amp;gt; MSwitch&lt;br /&gt;
#A MSwitch_Expert -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Lock_Quickedit -&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Thread über das Modul im {{Link2Forum|Topic=86199|LinkText=FHEM Forum}}&lt;br /&gt;
* {{Link2Forum|Topic=100119|Message=936495|LinkText=Gäste-WLAN der Fritzbox auswerten und Login per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=86199|Message=930133|LinkText=Schalten von vier Kanälen mit einem MSwitch-Device}}&lt;br /&gt;
* {{Link2Forum|Topic=99219|Message=926652|LinkText=Batterie-Überwachung. 1xTäglich per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=101091|Message=945389|LinkText=Licht (Alarm) in einem bestimmten Zeitraum schalten}}&lt;br /&gt;
* {{Link2Forum|Topic=100949|Message=944284|LinkText=Über Dummy-Schalter ein Timer (EIN/AUS) aktivieren}}&lt;br /&gt;
* {{Link2Forum|Topic=103083|Message=967710|LinkText=Ladezeit von Akku ermitteln u. Steckdose entsprechend schalten}}&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31480</id>
		<title>MSwitch</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31480"/>
		<updated>2019-11-01T20:02:25Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Tipps, Tricks, Kurzbeispiele */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[MSwitch]] ist ein Hilfsmodul, welches das Event- und/oder zeitgesteuerte Schalten von mehreren Devices oder das Ausführen von benutzerdefinierten Befehlssequenzen erlaubt.&lt;br /&gt;
&lt;br /&gt;
Die Stärke bzw. das Unterscheidungsmerkmal dieses Moduls liegt in der Konfigurierbarkeit über ein Webinterface. Diese Konfiguration kann jederzeit geändert oder erweitert werden. &lt;br /&gt;
&lt;br /&gt;
Byte09: &#039;&#039;Die Grundidee zu MSwitch kam mir, weil ich bei der Arbeit mit FHEM für meinen Geschmack zu viele Module für die verschiedenen Aufgaben brauchte - zu allem Überfluss alle mit unterschiedlicher Syntax. Zwar ist DOIF hiervon ausgenommen (da hiermit wohl auch fast jede Aufgabe lösbar ist), aber ich konnte mich leider nicht daran gewöhnen und somit wurde jedes DOIF für mich zu einem echten Projekt. Was ich wollte war ein Modul, mit dem ich alles erledigen kann. Daher entschloss ich mich schon nach fast einem knappen Jahr FHEM-Nutzung mein eigenes Modul zu schreiben, welches diese Anforderung erfüllt. MSwitch beinhaltet die Funktionalität aller bisherigen Hilfsmodule wie z.B. Notify, Doif, Watchdog, Dummy,( ab Modulversion 2.2 auch Sequenz ) es lassen sich all deren Funktionen umsetzen.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;MSwitch wird permanent - vorrangig nach meinen Bedürfnissen - weiterentwickelt, gerne nehme ich aber auch Anregungen von anderen Nutzern auf.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=MSwitch&lt;br /&gt;
|ModType=h&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=98_MSwitch.pm&lt;br /&gt;
|ModOwner=Byte09}}&lt;br /&gt;
&lt;br /&gt;
== Grundsätzliche Überlegungen ==&lt;br /&gt;
Um das Modul zu nutzen, muss man zuerst folgende Fragen beantworten:&lt;br /&gt;
&lt;br /&gt;
* Welches Gerät soll auslösen oder zu welcher Zeit soll eine Auslösung erfolgen.&lt;br /&gt;
: Dies ist der Trigger. Jedes Event aus dem Eventmonitor kann als Trigger dienen. Will man mehrere Geräte als gleichzeitige Auslöser betreiben, so muss das Device GLOBAL gewählt und die entsprechenden Geräte angegeben werden (dies erzeugt höhere Systemlast und ist nur im Expert-Modus verfügbar). Weiterhin kann auch zu fest definierten Zeiten, Zufallszeiten oder Intervallen, unabhängig von einem Trigger, geschaltet werden; auch eine Kombination beider Varianten ist möglich. Diese Einstellungen erfolgen im ersten Teil des Webinterfaces.&lt;br /&gt;
&lt;br /&gt;
* Welche Bedingungen sollen bei Auslösung erfüllt sein?&lt;br /&gt;
: Wenn diese Bedingungen erfüllt sind, werden Kommandos ausgelöst. Die Bedingungen werden im zweiten Teil des Webinterfaces eingegeben. Dabei unterscheidet das Modul zwischen zwei Kommando-Kanälen (cmd1 und cmd2) und den dazugehörigen Geräten.&lt;br /&gt;
&lt;br /&gt;
* Welche Kommandos sollen ausgelöst werden?&lt;br /&gt;
: Im dritten Teil des Webinterfaces werden dann die konkreten Kommandos eingegeben. Typischerweise wählt man dabei aus einer Liste der Kommandos aus, die die zugehörigen Geräte insgesamt aufweisen (also so, wie man auf den Geräteseiten selber Kommandos auswählt). Es gibt zudem ein so genanntes FreeCmd, das ein Geräteunabhängiges Kommando zulässt, beispielsweise reinen Perl-Code.&lt;br /&gt;
&lt;br /&gt;
* Welche weiteren Bedingungen sollen noch gelten?&lt;br /&gt;
: Hier sind Ereignisgesteuerte wie auch Zeitgesteuerte Bedingungen möglich. Diese Bedingungen werden auch in dem dritten Teil des Webinterfaces eingetragen. So sind Verzögerungen und Wiederholungen und weitere Bedingungen möglich.&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen, Installation und Grundbefehle ==&lt;br /&gt;
Das MSwitch-Modul ist ohne weitere Voraussetzungen nutzbar und wird derzeit in der Version 2.08 über FHEM Update verteilt. &lt;br /&gt;
&lt;br /&gt;
=== Definition und Einrichtung ===&lt;br /&gt;
Mit Hilfe von MSwitch kann man mehrere Devices gleichzeitig schalten. Diese Schaltungen befinden sich in zwei möglichen Zweigen bei MSwitch. Dabei unterscheidet man im Modul zwischen den beiden Kommandos cmd1 und cmd2. Die zu einem Kommando gehörenden Geräte werden wir auch Zweig nennen. Die einzelnen Devices jedes Zweiges können mit weiteren Schaltbedingungen versehen werden (zeit- oder ereignisgesteuert). &lt;br /&gt;
&lt;br /&gt;
Folgende Möglichkeiten zum definieren des MSwitch Devices stehen zur Verfügung:&lt;br /&gt;
:&amp;lt;code&amp;gt;define &amp;lt;name&amp;gt; MSwitch&amp;lt;/code&amp;gt;&lt;br /&gt;
Es wird ein leeres Device angelegt, das dann komplett über das Webinterface konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das define eines MSwitch Devices generiert lediglich eine &#039;leere Hülle&#039;. Alle relevante Einstellungen werden in Readings und/oder Hashes gespeichert. Daher stehen relevanten Daten &#039;&#039;nicht&#039;&#039; in der fhem.cfg! Vielmehr finden sich diese Daten in der Datei fhem.save (die Speicherung erfolgt durch den Befehl Fhemsave).&lt;br /&gt;
&lt;br /&gt;
=== set-Befehle ===&lt;br /&gt;
Es sind derzeit die folgenden set-Befehle implementiert.&lt;br /&gt;
&lt;br /&gt;
==== set active ====&lt;br /&gt;
Setzt das Device in den Status &#039;active&#039;.&lt;br /&gt;
&lt;br /&gt;
==== set inactive ====&lt;br /&gt;
Setzt das Device in den Status &#039;inactive&#039;, es werden keine Befehle mehr ausgeführt. Dieser Status entspricht dem Attribut &#039;disable&#039;, ist aber nicht mit dem roten Fragezeichen (fhem save) verbunden.&lt;br /&gt;
&lt;br /&gt;
==== set on/off [&amp;lt;parameter&amp;gt;]====&lt;br /&gt;
Setzt das Device in den Status &#039;on&#039; oder &#039;off&#039;. Alle Befehle der &#039;on/off-Zweige&#039; werden ausgeführt.&lt;br /&gt;
Optional kann den Befehlen &#039;on&#039; und &#039;off&#039; ein weiterer Parameter mit übergeben werden. Dieser wird im Reading &#039;Parameter&#039; hinterlegt und es kann sofort in &#039;Freecmds&#039; oder &#039;Conditions&#039; darauf zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
==== set reload_timer ====&lt;br /&gt;
Alle gesetzten Timer werden gelöscht und neu berechnet.&lt;br /&gt;
&lt;br /&gt;
==== set change_renamed &amp;lt;oldname&amp;gt; &amp;lt;newname&amp;gt; ====&lt;br /&gt;
Sollten sich Devicenammen im ausführenden Teil geändert habe (affected Devices, Conditions, etc.) so kann das MSwitch mit diesem Befehl angepasst werden, ohne alle Einstellungen neu einstellen zu müssen.&lt;br /&gt;
&lt;br /&gt;
==== set exec_cmd1 / set exec_cmd1 ID [&amp;lt;ID&amp;gt;] ====&lt;br /&gt;
Bewirkt das sofortige Ausführen des entsprechenden Befehlszweiges. Bei Angabe einer ID werden nur die Befehle mit der entsprechenden ID ausgeführt.&lt;br /&gt;
&lt;br /&gt;
==== set MSwitch_backup ====&lt;br /&gt;
Erstellt eine Backup-Datei aller MSwitch Devices unter ./fhem/MSwitch_backup.cfg.&lt;br /&gt;
&lt;br /&gt;
Daten dieser Datei können im Bedarfsfall für einzelne oder gleichzeitig alle MSwitch Devices wieder zurückgespielt (hergestellt) werden.&lt;br /&gt;
&lt;br /&gt;
==== set del_delays ====&lt;br /&gt;
Löscht alle anstehenden, verzögerten Befehle (delays).&lt;br /&gt;
&lt;br /&gt;
==== set reset_cmd_count:1,2 ====&lt;br /&gt;
Löscht das entsprechende EVT_CMD_COUNT - Reading (entspricht Rückstellung auf &#039;0&#039;).&lt;br /&gt;
&lt;br /&gt;
==== set fakeevent [&amp;lt;device&amp;gt;]:&amp;lt;reading&amp;gt;:&amp;lt;arg&amp;gt; ====&lt;br /&gt;
Beispiel: &amp;lt;device&amp;gt; fakeevent state:on&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ob der Name (&amp;lt;device&amp;gt;) angegeben werden muss, oder nicht, ist abhängig davon, ob auf ein einzelnes Device, oder GLOBAL getriggert wird. Bei GLOBALEN Triggern muss das Device mit angegeben werden. Wird auf ein Device getriggert, so wird das Device automatisch gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit diesem Befehl kann das MSwitch Device neu getriggert werden, indem hier ein Event &#039;gefaked&#039; wird. Das MSwitch Device reagiert dann so, als wäre dieses Event vom getriggerten Gerät generiert worden. &lt;br /&gt;
&lt;br /&gt;
Dieses kann nötig sein, um z.B. einen Watchdog zu realisieren, in dem es nötig ist, dass sich das MSwitch Device mit einem bestimmten Event selber neu triggert - ggf. mit einem entsprechenden Delay (affected Device muss dafür u.A. des MSwitch Device selber sein).&lt;br /&gt;
&lt;br /&gt;
Es wird hierbei KEIN echtes Event generiert welches das System beeinflusst, sondern ausschließlich ein MSwitch-Interner Befehl umgesetzt!&lt;br /&gt;
&lt;br /&gt;
Bei dem Einsatz dieser Möglichkeit sollte das Attribut &#039;MSwitch_Safemode&#039; UNBEDINGT aktiviert sein, da &#039;Experimente&#039; hier schnell in einer Endlosschleife enden können, die nur durch ein Reboot unterbrochen werden kann. &lt;br /&gt;
&lt;br /&gt;
Ggf. werde ich hier sogar eine entsprechende Änderung vornehmen, dass dieser Befehl nur zur Verfügung steht, wenn Safemode aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
=== get-Befehle ===&lt;br /&gt;
==== get show_timer [&amp;lt;show&amp;gt;&amp;lt;delete&amp;gt;] ====&lt;br /&gt;
;Show&lt;br /&gt;
:Zeigt alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren.&lt;br /&gt;
;Delete&lt;br /&gt;
:Löscht alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren. Schaltbefehle basierend auf rein zeitabhängigen Angaben werden neu berechnet und gesetzt.&lt;br /&gt;
&lt;br /&gt;
==== get restore_MSwitch_data [&amp;lt;this_device&amp;gt;&amp;lt;all_devices&amp;gt;] ====&lt;br /&gt;
;this_device&lt;br /&gt;
:Stellt die Daten des Devices aus der Backupdatei wieder her, sofern diese in der Backupdatei gefunden werden (gesucht wird hier nach dem Namen des Devices).&lt;br /&gt;
;all_devices&lt;br /&gt;
:Stellt die Daten aller MSwitch Devices wieder her, sofern diese in der Backupdatei vorhanden sind. Diese Aktion kann einige Zeit in Anspruch nehmen und wird daher im Hintergrund (nonblocking) ausgeführt. Nach Beendigung erfolgt eine Benachrichtigung.&lt;br /&gt;
&lt;br /&gt;
Die Devices sind nach einem Restore funktionsfähig. Empfohlen wird ein Neustart von FHEM.&lt;br /&gt;
&lt;br /&gt;
==== get_config ==== &lt;br /&gt;
Zeigt die Konfigurationsdatei des MSwitchdevices an; diese kann in dem Fenster editiert werden. Das sollte nur von erfahrenen Usern getan werden! Im Normalfall sollte das Device nur über die Weboberfläche konfiguriert werden und eine falsche Konfiguration kann hier zu einem FHEM Absturz führen.&lt;br /&gt;
&lt;br /&gt;
==== get_support_info ==== &lt;br /&gt;
Öffnet ein Fenster mit einer formatierten Ansicht aller Einstellungen des Devices. Bei Supportanfragen sollte dieses immer mit geposted werden.&lt;br /&gt;
&lt;br /&gt;
==== get_MSwitch_preconf ====&lt;br /&gt;
Lädt vorkonfigurierte MSwitch-Devices. Diese Option ist nur dann vorhanden, wenn das Aktualisieren dieser vorkonfigurierten Devices im FHEM Update aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
Diese kann durch ein einmaliges Update erfolgen mit:&lt;br /&gt;
:&amp;lt;code&amp;gt;update all https://raw.githubusercontent.com/Byte009/MSwitch_Addons/master/controls_mswitchaddons.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Webinterface ==&lt;br /&gt;
MSwitch wird im Wesentlichen über das Webinterface eingerichtet. Wählt man das folgende Attribut&lt;br /&gt;
:&amp;lt;code&amp;gt;attr &amp;lt;name&amp;gt; MSwitch_Help 1&amp;lt;/code&amp;gt;&lt;br /&gt;
so wird im Modul selber eine sehr umfangreiche Hilfe angezeigt. Über das gesamte Webinterface hinweg erscheinen kleine Fragezeichen, die man anklicken kann und die beschreiben, was in dem jeweiligen Textfeld sinnvollerweise einzugeben ist bzw. was das Modul an dieser Stelle erwartet.&lt;br /&gt;
&lt;br /&gt;
Das Webinterface besteht aus vier Teilen. Änderungen in jedem Abschnitt müssen in dem jeweiligen Teil bestätigt werden und auch nur diese werden gespeichert. Bevor ein weiterer Teil bearbeitet wird, sollten Änderungen gespeichert werden, sie gehen sonst verloren.&lt;br /&gt;
&lt;br /&gt;
=== Trigger device/time ===&lt;br /&gt;
==== Trigger Device ====&lt;br /&gt;
In diesem Feld wird das Device ausgewählt, dessen Events eine Aktion auslösen sollen. Dazu werden alle verfügbaren Devices in einem Dropdownfeld angeboten.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es eine Auswahl &#039;GLOBAL&#039;, wenn das Attribut &#039;MSwitch_Expert&#039; gesetzt ist. Bei Auswahl dieser Option werden &#039;&#039;&#039;alle&#039;&#039;&#039; von FHEM generierten Events durch das MSwitch Device weiterverarbeitet, eine weitere Begrenzung der aktivierenden Events kann (und sollte) dann in einem folgenden Eingabefeld erfolgen, um die Systemlast zu reduzieren.&lt;br /&gt;
&lt;br /&gt;
==== Trigger Device Global Whitelist ====&lt;br /&gt;
Dieses Feld ist nur verfügbar, wenn als Trigger &#039;GLOBAL&#039; gewählt wurde.&lt;br /&gt;
&lt;br /&gt;
Hier kann die Liste eingehender Events weiter eingeschränkt werden. Es handelt sich um eine Whitelist, d.h., wenn es keine Einträge gibt, werden Events aller Devices verarbeitet. Sobald ein oder mehrere Einträge gemacht werden, werden nur noch Events der hier benannten Devices verarbeitet. Als Angabe können hier Devices benannt werden oder ganze DeviceTypen (z.B. TYPE=FS20). Mehrere Angaben sind durch Komma zu trennen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:MSwitchWebinterface1.png|400px|thumb|right|Webinterface, oben]]&lt;br /&gt;
Im gezeigten Beispiel wurde GLOBAL gewählt, weil nicht ein einzelnes Device, sondern eine Kombination aus zwei Geräten auslösen soll. Es werden also alle Ereignisse betrachtet, wobei die Whitelist dann auf die Devices Schlafzimmer (ein Temperaturmessgerät) und Schlafzimmerfenster (ein [[HM-Sec-SCo Tür-Fensterkontakt, optisch|optischer Kontakt]]) einschränkt. &lt;br /&gt;
&lt;br /&gt;
==== Trigger time ==== &lt;br /&gt;
Es besteht die Möglichkeit, das Modul (neben den Events) zu festen Zeiten auszulösen. Dann wären in die leer stehenden Zeilen bei &amp;quot;at&amp;quot; entsprechende Termine einzutragen. Zeitangaben erfolgen durch [STUNDEN:MINUTEN|TAGE], wobei die Tage von 1-7 gezählt werden (1 steht für Montag, 7 für Sonntag usw.). &lt;br /&gt;
Mehrere Zeitvorgaben können direkt aneinandergereiht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [17:00|1][18:30|23] den Trigger montags um 17 Uhr auslösen und dienstags sowie mittwochs um 18:30 Uhr.&lt;br /&gt;
Bei [00:10*20:00-21:00] würde der Schaltbefehl von 21 Uhr bis 21 Uhr alle 10 Minuten ausgeführt. Bei [?20:00-21:00] würde der Schaltbefehl zu einem zufälligen Zeitpunkt zwischen 20 und 21 Uhr ausgeführt.  [20:00|$we] bedeutet, dass nur am Wochenende um 20:00 geschaltet wird.&lt;br /&gt;
&lt;br /&gt;
==== Trigger conditions ====&lt;br /&gt;
Hier kann die Angabe von Bedingungen erfolgen, die zusätzlich zu dem triggernden Device erfüllt sein müssen.&lt;br /&gt;
Diese Bedingungen sind eng an DOIF-Syntax angelehnt. Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich.&lt;br /&gt;
&lt;br /&gt;
Wird in diesem Feld keine Angabe gemacht, so erfolgt der Schaltvorgang nur durch das triggernde Device ohne weitere Bedingungen.&lt;br /&gt;
&lt;br /&gt;
;Zeitabhängigkeit&lt;br /&gt;
:[19:10-23:00] - Trigger des Devices erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
;Readingabhängige Trigger&lt;br /&gt;
:[Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Trigger des Device erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
:Werden Readings mit Strings abgefragt (on,off,etc.), ist statt des Gleichheitszeichens &amp;quot;=&amp;quot; der Operator &amp;quot;eq&amp;quot; zu nutzen, der String muss in Anführungszeichen &amp;quot;&amp;quot; gesetzt werden.&lt;br /&gt;
;mehrere Beispiele&lt;br /&gt;
:[19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
:[19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
:[10:00-11:00|13] - schaltet Montag und Mittwoch zwischen 10 Uhr und 11 Uhr.&lt;br /&gt;
:[{ sunset() }-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
:{ !$we } löst den Schaltvorgang nur Werktagen an aus.&lt;br /&gt;
:{ $we } löst den Schaltvorgang nur an Wochenenden, Feiertagen aus.&lt;br /&gt;
&lt;br /&gt;
Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (beispielsweise würde dann am Mittwoch noch der Schaltvorgang erfolgen, obwohl als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
Bedingungen in diesem Feld gelten nur für auslösende Trigger eines Devices und haben keinen Einfluss auf zeitgesteuerte Auslöser.&lt;br /&gt;
&lt;br /&gt;
=== Trigger details ===&lt;br /&gt;
[[Datei:MSwitchWebinterface2.png|600px|thumb|right|Webinterface, Mitte]]&lt;br /&gt;
Während im obigen Feld das Device ausgewählt  werden konnte, wird hier das Ereignis festgelegt. Das Eingabefeld besteht aus mehreren Einzelfeldern.&lt;br /&gt;
&lt;br /&gt;
Im abgebildeten Fall wird cmd1 ausgelöst, wenn der Zustand des Schlafzimmerfenster-Sensors meldet, dass das Fenster offen ist. Cmd2 wird ausgelöst, wenn die Temperatur des Schlafzimmersensors unter einen bestimmten Wert fallen wird.&lt;br /&gt;
&lt;br /&gt;
==== execute &#039;cmd1/cmd2&#039;  ====&lt;br /&gt;
Hier kann  aus einer vorbelegten Dropdownliste ausgewählt werden, welches ankommende Event den entsprechenden Befehlszweig auslösen soll. In dieser Liste werden bei entsprechender Einstellung alle ankommenden Events eines vorher definierten Devices gespeichert. In einem weiteren Feld (siehe unten) können Events manuell zugefügt werden.&lt;br /&gt;
&lt;br /&gt;
==== Save incomming events ====&lt;br /&gt;
Bei Aktivierung dieser Option werden alle ankommenden Events des oben definierten Devices (oder Global) gespeichert und in entsprechenden Dropdownlisten angeboten.&lt;br /&gt;
&lt;br /&gt;
Da hier doch erhebliche Datenmengen anfallen können (je nach Device) wird empfohlen, diese Option nach der Konfiguration des Devices zu deaktivieren.&lt;br /&gt;
&lt;br /&gt;
==== add event ====&lt;br /&gt;
Hier besteht die Möglichkeit, unabhängig von der Option, ankommende Events automatisch zu speichern. Manuell Events anzulegen, die in den Dropdownliste zur Auswahl angeboten werden, ohne das entsprechendes Event erst vom Device geliefert werden muss.&lt;br /&gt;
&lt;br /&gt;
Es können mehrere Events gleichzeitig eingegeben werden, eine Trennung erfolgt durch &amp;quot; , &amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Hier ist zu unterscheiden, ob das gewählte triggernde Device ein einfaches Device ist oder ob der Trigger &#039;GLOBAL&#039; ist.&lt;br /&gt;
Bei triggernden Devices können Events in folgendem Formaten zugefügt werden:&lt;br /&gt;
&lt;br /&gt;
- *                                                    - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:wert   (z.b. state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:*      (z.b. state:* )                       - Aktion erfolgt auf die Events &amp;quot;state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:(wert1/wert2/wert3) (z.b. state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;state:left&amp;quot; oder &amp;quot;state:right&amp;quot; etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Falls auf &#039;GLOBALE&#039; Events getriggert wird, muss das auslösende Device vorangestellt werden:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
- *                                                           - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:wert   (z.b. device:state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;device:state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:*      (z.b. device:state:* )                       - Aktion erfolgt auf die Events &amp;quot;device:state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:(wert1/wert2/wert3) (z.b. device:state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;device:state:left&amp;quot; oder &amp;quot;devicestate:right&amp;quot; etc.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Device kann auch hier gegen &amp;quot;*&amp;quot; ersetzt werden (*:state:on). In diesem Fall erfolgt eine Aktion auf alle Events die z.B. &amp;quot;state:on&amp;quot; enthalten, egal welches Device triggert.&lt;br /&gt;
&lt;br /&gt;
==== test event ====&lt;br /&gt;
Dieses Feld wird angeboten, wenn entsprechende vom Triggerdevice gelieferte Events gespeichert wurden.&lt;br /&gt;
&lt;br /&gt;
Durch Auslösen dieser Funktion wird das Event simuliert und entsprechende definierte Aktionen ausgelöst. Diese Funktion dient ausschließlich zum Testen der eingestellten Konfiguration. Alle entsprechenden Befehle werden ausgeführt, als würde das Event real eintreffen.&lt;br /&gt;
&lt;br /&gt;
==== apply filter to saved events ====&lt;br /&gt;
Beschreibung folgt&lt;br /&gt;
&lt;br /&gt;
==== clear saved event ====&lt;br /&gt;
Es werden alle gespeicherten Events gelöscht.&lt;br /&gt;
&lt;br /&gt;
Ausnahme: Events, die als Trigger eingestellt sind, bleiben erhalten.&lt;br /&gt;
&lt;br /&gt;
=== Affected devices ===&lt;br /&gt;
[[Datei:MSwitch_Screen_5.png|mini|rechts|affected devices]]&lt;br /&gt;
Dieser Abschnitt beinhaltet die Auswahl der Devices, die auf ein Event reagieren sollen.&lt;br /&gt;
&lt;br /&gt;
In dem Auswahlfeld werden alle Devices angeboten, die eines der folgenden Kriterien erfüllen:&lt;br /&gt;
# Die Abfrage &amp;quot;set Device ?&amp;quot; liefert einen Befehlssatz&lt;br /&gt;
# Das Attribut &#039;webcmd&#039; des Devices enthält Einträge&lt;br /&gt;
# Das Attribut &#039;MSwitch_Activate_MSwitchcmds&#039; ist aktiviert und das Attribut &#039;MSwitchcmds&#039; des betreffenden Devices enthält einen Befehlssatz&lt;br /&gt;
&lt;br /&gt;
Einzige Ausnahme ist der erste Listeneintrag &#039;FreeCMD&#039;. Die Auswahl dieses Eintrages bietet später die Möglichkeit Befehle auszuführen, die nicht an ein Device gebunden sind. Der Code in einem FreeCmd kann entweder reiner FHEM-Code sein ( set device on ) oder reiner Perl-Code. Wenn es sich um reinen Perl-Code handelt, ist dieser in geschweifte Klammen zu setzen { Perl-Code }.&lt;br /&gt;
&lt;br /&gt;
=== Device actions ===&lt;br /&gt;
[[Datei:Webinterface3.png|mini|rechts|device_actions]]&lt;br /&gt;
Hier stellt man die auszuführenden Aktionen der eingestellten Devices ein. Im ersten Abschnitt oben befindet sich ein FreeCmd, mit dem beliebige Kommandos eingetragen werden können. Im abgebildeten Beispiel ist dies sogar selbst definierter Perl-Code (die Funktion DebianMail sendet eine Mail). &lt;br /&gt;
&lt;br /&gt;
==== MSwitch cmd1/cmd2:  ====&lt;br /&gt;
Man wählt den Befehl aus dem betreffenden Device aus. Bei freien Textfeldern (wie im Fall des FreeCmd) wird der Befehl eingegeben.&lt;br /&gt;
&lt;br /&gt;
Es werden alle verfügbaren Befehle des Devices zur Auswahl angeboten. Je nach Attribut-Einstellungen werden Einträge aus entsprechenden &#039;webcmds&amp;quot; oder &#039;MSwitchcmds&#039; einbezogen. In Abhängigkeit des Befehls stehen unter Umständen weitere Felder oder Widgets zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
05.04.2018 NEU: Auswahlfeld &#039;MSwitchtoggle&#039; -&amp;gt; Beschreibung wird noch ergänzt !&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 condition  ====&lt;br /&gt;
Mit diesem Feld kann die Ausführung des Befehls von weiteren Bedingungen abhängig gemacht werden. Bei der Abfrage von Readings nach Strings (on, off, etc.) ist statt &amp;quot;=&amp;quot; &amp;quot;eq&amp;quot; zu nutzen und der String muss in &amp;quot;x&amp;quot; gesetzt werden. Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
#Zeitabhängiges schalten: [19:10-23:00] - Schaltbefehl erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
#Readingabhängiges schalten [Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Schaltbefehl erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
&lt;br /&gt;
Soll nur an bestimmten Wochentagen geschaltet werden, muss eine Zeitangabe gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [10:00-11:00|13] den Schaltvorgang nur Montag und Mittwoch zwischen 10 Uhr und 11 Uhr auslösen. Hierbei zählen die Wochentage von 1-7 für Montag-Sonntag.&lt;br /&gt;
&lt;br /&gt;
Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich:&lt;br /&gt;
* [19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
* [19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
* [{sunset()}-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
* { !$we } löst den Schaltvorgang nur Werktagen aus&lt;br /&gt;
* { $we } löst den Schaltvorgang nur Wochenenden, Feiertagen aus&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung:&#039;&#039;&#039; Bei Anwendung der geschweiften Klammern zur Einleitung eines Perl Ausdrucks ist unbedingt auf die Leerzeichen hinter und vor der Klammer zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (zum Beispiel würde auch am Mittwoch noch der Schaltvorgang erfolgen, wenn als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
; $EVENT:&lt;br /&gt;
: Die Variable EVENT enthält den auslösenden Trigger, d.h. es kann eine Reaktion in direkter Abhängigkeit zum auslösenden Trigger erfolgen.&lt;br /&gt;
&lt;br /&gt;
[$EVENT] eq &amp;quot;state:on&amp;quot; würde den Kommandozweig nur dann ausführen, wenn der auslösende Trigger &amp;quot;state:on&amp;quot; war. Wichtig ist dieses, wenn bei den Triggerdetails nicht schon auf ein bestimmtes Event getriggert wird, sondern hier durch die Nutzung eines Wildcards (*) auf alle Events getriggert wird, oder auf alle Events eines Readings z.B. (state:*).&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 delay  ====&lt;br /&gt;
Ein Eintrag in diesem Feld führt zur verzögerten Ausführung des Befehls nach Eintreffen des Events. Dabei kann der Befehl ohne weitere Prüfung der Bedingung ausgelöst werden. Es ist aber auch möglich, dass die Bedingung bei Ausführung erneut geprüft wird. Die Zeitangabe muss im Format hh:mm:ss vorliegen.&lt;br /&gt;
&lt;br /&gt;
Statt einer unmittelbaren Zeitangabe kann hier auch ein Verweis auf ein Reading eines Devices erfolgen :&amp;lt;br&amp;gt;&lt;br /&gt;
[NAME.reading] des Devices -&amp;gt;z.B. [dummy.state]&lt;br /&gt;
&lt;br /&gt;
==== add action  ====&lt;br /&gt;
Mit diesem Button kann ein weiteres Eingabefeld für das entsprechende Device angelegt werden, um z.B. einen weiteren Befehl (ggf.) zeitverzögert auszuführen.&lt;br /&gt;
&lt;br /&gt;
==== delete this action  ====&lt;br /&gt;
Mit diesem Button wird der entsprechende Befehl für das Device gelöscht.&lt;br /&gt;
&lt;br /&gt;
==== check condition  ====&lt;br /&gt;
[[Datei:MSwitch_Screen_7.png|mini|rechts|check]]&lt;br /&gt;
Die angegebenen &#039;conditions&#039; werden in Zusammenhang mit ggf. ausgewählten Devices auf Syntax und Ergebnis geprüft. Es erfolgt eine Ausgabe des Prüfungsergebnisses.&lt;br /&gt;
&lt;br /&gt;
==== Repeat und Repeatdelay ====&lt;br /&gt;
Man kann mehrfache Wiederholungen erzwingen. Repeat gibt dabei an, wie oft das Kommando wiederholt wird (Anzahl). Repeatdelay gibt an, wie viel Sekunden zwischen einzelnen Wiederholungen liegen sollen.&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Folgende Attribute stehen zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Debug (0:1:2:3:4) ===&lt;br /&gt;
0 - Abgeschaltet&amp;lt;br&amp;gt;&lt;br /&gt;
1 - Schaltet Felder zum testen der Conditionstrings etc. an&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Alle ausgehenden Befehle werden nur simuliert und nicht ausgeführt. Es erfolgt eine Protokollierung in einer separaten Datei. Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Es erfolgt eine Protokollierung in einer separaten Datei. Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
4 - erweiterte Debug-Funktion (nur für Entwicklung - wechselnde Funktion )&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Expert (0:1) ===&lt;br /&gt;
In der Liste der möglichen Trigger erscheint das Selectfeld &#039;GLOBAL&#039;. Dieses ermöglicht das Setzen eines Triggers auf alle Events und damit nicht nur auf einzelne Devices. In einem weiteren Feld kann eine weitere Selektion der triggernden Events erfolgen.&lt;br /&gt;
&lt;br /&gt;
Es stehen weitere Felder &#039;Repeats&#039; und &#039;Repeatdelay in sec&#039; zur Verfügung. Eine hier getätigte Einstellung bewirkt X-fache Wiederholung von gesetzten Befehlen im Abstand der gesetzten Sekunden.&lt;br /&gt;
&lt;br /&gt;
Weiterhin kann über das Auswahlfeld &#039;priotity&#039; bei jedem &#039;affectes device&#039; die Reihenfolge beim abarbeiten der Befehle beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequenz &amp;lt;Suchmuster&amp;gt; ===&lt;br /&gt;
In diesem Attribut können ein oder mehrere Suchmuster angegeben werden ,die eine Schaltsequenz darstellen und vom Device erkannt werden.&lt;br /&gt;
&lt;br /&gt;
Die Angabe muss folgende Syntax haben:&lt;br /&gt;
:&amp;lt;code&amp;gt;Device1:reading1:event1 Device1:reading1:event1-2 Device1:reading1:event1-3/..../....&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mehrere Suchmuster müssen durch &amp;quot;/&amp;quot; getrennt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
:&amp;lt;code&amp;gt;Dummy:state:on Dummy:state:off Dummy:state:on&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erkennt das Device dieses Suchmuster in den Schaltvorgängen des Devices (Dummy), wird das Reading &amp;quot;SEQUENCE&amp;quot; auf &amp;quot;match&amp;quot; gesetzt, das Reading &amp;quot;SEQUENCE_NUMBER&amp;quot; auf die Nummer der gefundenen Sequenz, wenn es mehrere Suchmuster gibt. Beide Readings können in den &amp;quot;Conditions&amp;quot; eines Schaltbefehles abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequence_time &amp;lt;Zeit in Sekunden&amp;gt; ===&lt;br /&gt;
Beinhaltet die Zeit in Sekunden, die es dauern darf, um eine Sequenz vollständig auszuführen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Extensions (0:1) ===&lt;br /&gt;
Es wird eine zusätzliche Schaltoption &#039;MSwitchToggle&#039; in den Geräten angeboten. Diese kann genutzt werden, wenn zuschaltende Geräte eine Togglefunktion nicht von Haus aus anbieten.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe muss in folgendem Format gemacht werden:&lt;br /&gt;
:&amp;lt;code&amp;gt;on/off/state/suchmuster1/suchmuster2&amp;lt;/code&amp;gt;, wobei die letzten drei Angaben optional sind.&lt;br /&gt;
&lt;br /&gt;
Funktion: Bei Ausführung des Befehls wird das Gerät &#039;on&#039; oder &#039;off&#039; geschaltet (on/off), Voraussetzung ist, dass der &#039;state&#039; dieses Gerätes auch den &#039;state on&#039; oder &#039;off&#039; annimmt. Sollte dieses nicht der Fall sein, so kann mit dem Feld &#039;state&#039; angegeben werden, in welchem Reading der aktuelle Status vorkommt und wie dieser lautet (suchmuster1/suchmuster2). Dieses &#039;state&#039; kann mehrere Angaben enthalten, das Vorkommen der Suchmuster ist aber Voraussetzung.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Delete_Delays (0:1) ===&lt;br /&gt;
Bewirkt das Löschen aller anstehende Timer (Delays) bei dem Auftreten eines erneuten, passenden Events. Bei der Option &#039;0&#039; bleiben bereits gesetzte Delays aus einem vorherigen, getriggertem Event erhalten und werden ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1)&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Devicecmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz liefern (bei Abfrage set DEVICE ?).&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Webcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut Webcmd hinterlegt haben. Die in Webcmd hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten.&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Activate_MSwitchcmds (0:1) ===&lt;br /&gt;
Fügt jedem vorhandenen Device as Attribut &#039;MSwitchcmd&#039; hinzu.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_MSwitchcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut MSwitchcmds hinterlegt haben. Die in MSwitchcmds hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten. Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr Angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Lock_Quickedit (0:1) ===&lt;br /&gt;
Voreinstellung für die Auswahlliste &#039;Affected Devices&#039;. Bei der Option (1) ist diese voreingestellt gesperrt und kann nur über einen zusätzlichen Button geändert werden. Da es sich hier um ein Feld mit der Möglichkeit einer Mehrfacheingabe handelt handelt ist die Voreinstellung 1, um versehentliche nicht gewünschte Änderungen zu vermeiden (Auswahl einer Option ohne &#039;Strg&#039; bewirkt das löschen aller bereits gesetzten Optionen).&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay (0:10:20:30:60) ===&lt;br /&gt;
Diese Einstellung beeinflusst den Start von MSwitch nach einem FHEM Start. MSwitch ignoriert für die angegebene Zeit in Sekunden alle eingehenden Events um u.a. Startverzögerungen zu vermeiden. Bei nicht gesetztem Attribut gilt hier eine Zeit von 30 Sekunden. Diese sollte auch nur in Ausnahmefällen bzw. bei besonderem Bedarf geändert werden.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (30).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Ignore_Types ===&lt;br /&gt;
Beinhaltet eine Liste von Device&#039;&#039;typen&#039;&#039;, die in den Auswahllisten &#039;&#039;nicht&#039;&#039; dargestellt werden. Hier ist es sinnvoll, Devicetypen einzutragen, die in aller Regel nicht geschaltet werden oder nicht geschaltet werden können, um die Auswahllisten übersichtlicher zu halten. Einzelne Devicetypen sind durch Leerzeichen zu trennen.&lt;br /&gt;
&lt;br /&gt;
Voreinstellung: notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe kann hier in 2 Arten getätigt werden:&lt;br /&gt;
# eine Liste von devicetypen.&lt;br /&gt;
# Angabe einer devspec z.B. &amp;quot;TYPE=watchdog&amp;quot;. Hier ist zu beachten, dass in diesem Fall alle Geräte in die Ignoreliste einbezogen werden, die NICHT der devspec entsprechen. Weiterhin muss die devspec in Anführungszeichen gesetzt werden!&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Trigger_Filter ===&lt;br /&gt;
Beinhaltet eine Liste von Events, die bei eingehenden Events unberücksichtigt bleiben. Diese werde dann auch nicht gespeichert.&lt;br /&gt;
&lt;br /&gt;
Hier kann mit Wildcards (*) gearbeitet werden. Einzelne Events sind durch Komma &#039;,&#039; zu trennen.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (keine).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Wait (sec)===&lt;br /&gt;
Bei gesetztem Attribut (Zeit in Sekunden) nimmt Das MSwitch Device für den eingestellten Zeitraum keine Befehle mehr entgegen und ignoriert eingehende Events&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Event_Id_Distributor ===&lt;br /&gt;
Dieses Attribut hat nur dann eine Funktion, wenn auch das Attribut &#039;MSwitchExpert&#039; auf &#039;1&#039; gesetzt ist.&lt;br /&gt;
Hier können verschiedene auslösende Events auf Aktionen mit angegebenen IDs umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Sollte bei den &#039;trigger details :&#039; in einem Zweig ( cmd1 ) z.B. auf mehrere Events getriggert werden ( regex z.B. state:(on|off) ) so werden für beide Events jeweils der Zweig &#039;cmd1&#039; - alle  Aktionen ohneID - ausgeführt. Durch entsprechende Einträge kann für entsprechende Events auf eine Aktion umgeleitet werden, für die eine ID definiert ist. Die Syntax lautet:&lt;br /&gt;
:&amp;lt;code&amp;gt;state:on=&amp;gt;cmd1 ID 1,2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden bei auslösendem Event &#039;state:on&#039; nur die Aktionen aus cmd1 mit den IDs 1 und 2 ausgeführt. Mehrere Angaben sind durch new Line zu trennen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Selftrigger_always (0,1)===&lt;br /&gt;
(dieses Attribut steht ab Modulversion 2.5 zur Verfügung)&lt;br /&gt;
&lt;br /&gt;
Die Aktivierung dieses Attributes (1) bewirkt, dass alle SET Aktionen des Devices einen (internen) Event auslösen, auf die das Device selber reagiert. Diese Option kann zusätzlich zu einem vorhandenen Trigger aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Diese Events sind lediglich Device intern, d.h es werden keine Modulübergreifenden Events ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Auftretende und auswertbare interne Events haben immer folgendes Format und können darüber ausgewertet werden.&lt;br /&gt;
&lt;br /&gt;
MSwitch_Self:aktion:wert &lt;br /&gt;
MSwitch_Self:pct:100&lt;br /&gt;
&lt;br /&gt;
Es werden nur interne Events für set-Aktionen ausgelöst, die im Attribut setlist hinterlegt sind.&lt;br /&gt;
&lt;br /&gt;
Als weitere Besonderheit unterliegen diese internen Events nicht dem &#039;wait&#039; Befehl/Attribut.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Mode (Notify,Full,Toggle,Dummy)===&lt;br /&gt;
Schaltet das Modul zwischen verschiedenen Modi um, mit entsprechend angepasster Weboberfläche.&lt;br /&gt;
&lt;br /&gt;
==== Notify ====&lt;br /&gt;
Das Device kann nicht manuell umgeschaltet werden. Es gibt nur zwei ausführbare Zweige (execute &#039;cmd1&#039; commands und execute &#039;cmd2&#039; commands). Der Status des Devices wird nicht als &#039;on&#039; oder &#039;off&#039; angezeigt, sondern lediglich als &#039;active&#039;&lt;br /&gt;
&lt;br /&gt;
Dieser Mode ist am ehesten mit einem Notify zu Vergleichen.&lt;br /&gt;
&lt;br /&gt;
==== Full ====&lt;br /&gt;
Es stehen alle Funktionen zur Verfügung.&lt;br /&gt;
==== Toggle ====&lt;br /&gt;
Sehr vereinfachter Mode. Es stehen keine verschiedenen Zweige zur Verfügung. Hier ist das Device manuell schaltbar und wird bei jedem definierten Event &#039;Umgeschaltet&#039;, entsprechend definierte Befehle für &#039;cmd1&#039; oder &#039;cmd2&#039; werden ausgeführt.&lt;br /&gt;
==== Dummy====&lt;br /&gt;
ACHTUNG: Funktionsänderung mit V2.61&lt;br /&gt;
&lt;br /&gt;
Der Mode &#039;Dummy&#039; ist ein eingeschränkter Modus. &lt;br /&gt;
Dieser bietet die Funktionalität eines Dummys kombiniert mit der Funktionalität eines Notifys und kann somit die gerne genutzte Kombination Dummy-Notify gegen ein Device ersetzen.&lt;br /&gt;
&lt;br /&gt;
Achtung: Devices die einmal in dem Modus &#039;Dummy&#039; gesetzt wurden können nicht wieder in einen anderen Mode geschaltet werden ! &lt;br /&gt;
&lt;br /&gt;
Der Dummy-Mode kann nur in einem neu angelegtem, leeren MSwitch aktiviert werden. Sobald ein angelegtes MSwitch einmal verändert wurde (modify trigger etc.) ist ein Umschalten nicht mehr möglich und die Option nicht mehr verfügbar.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Condition_Time (0,1)===&lt;br /&gt;
In der Grundeinstellung (0) werden für das zeitgesteuerte Schalten keine definierten Conditionen im Feld &#039;Trigger condition&#039; überprüft, sondern die Schaltbefehle werden in jedem Fall ausgeführt. Mit der Einstellung (1) wird diese Überprüfung auch für zeitgesteuerte Befehle zugeschaltet.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Time (HH:MM:SS-HH:MM:SS)===&lt;br /&gt;
Bei Aktivierung wird vor jedem Ausführen eines verzögerten Befehls ( Delay ) eine Zufallszeit generiert, die im Rahme der hier angegebenen Zeitspanne liegt. Auf diese Zufallszahl kann in den Delays zugegriffen werden, durch die Angabe &#039;[random]&#039; statt einer direkten Zeitangabe. Bei nicht gesetztem Attribut ergibt die Angabe von &#039; [random] &#039; hier immer &#039;00:00:00&#039;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Number ===&lt;br /&gt;
Bei Aktivierung dieses Attributes (der Inhalt kann einen beliebige Zahl sein) werden vom Device 2 Readings angelegt (Device:RandomNr) und (Device:RandomNr1). RandomNr wird vor jedem Ausführen eines Befehls aktualisiert und neu generiert, d.h wenn ein MSwitch Device mehrere Geräte schaltet, wird (auch in einem Durchgang) vor jedem Befehl dieses Reading neu gesetzt. RandomNr1 wird lediglich bei Ausführung des MSwitch Devices einmal neu gesetzt, d.h. nicht vor jedem Befehl der ausgeführt wird.&lt;br /&gt;
Die Readings werden mit einer Zufallszahl zwischen 0 und dem hier eingestellten Wert gesetzt.&lt;br /&gt;
&lt;br /&gt;
Auf diese Readings kann in jeder Condition mit z.B. &#039;[$NAME:ReadingNr1] = 1&#039; zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
D.h., das in der Condition angegebene Reading ( [$NAME:ReadingNr1] ) muss in diesem Fall den Wert 1 angenommen haben, ansonsten wird der Befehl nicht ausgeführt. &lt;br /&gt;
Der Befehl wird somit nur mit einer Wahrscheinlichkeit von 1 zu ( gesetzter Wert im Attr. ) ausgeführt.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Reset_EVT_CMD1(2)_COUNT ===&lt;br /&gt;
Bei Aktivierung dieses Attributes steht in den Readings das Reading &#039;EVT_CMD1_COUNT&#039; bzw. &#039;EVT_CMD2_COUNT&#039; zur Verfügung. Dieses kann in den Conditions genutzt werden, um z.B. nur bei jedem x-ten Eintreffen eines auslösenden Events einen Befehl auszuführen. Bei jedem Eintreffen eines gültigen Events werden die Zähler um 1 erhöht (für den jeweiligen Zweig). &lt;br /&gt;
Ist hier der Wert &#039;0&#039; eingetragen, wird der Zähler fortlaufend (endlos) erhöht. Wird ein Wert größer 0 eingetragen, wird der Zähler mit Erreichen dieses Wertes automatisch wieder auf Null gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit Löschen dieses Attributes werden die entsprechenden Readings ebenfalls gelöscht.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Safemode (0:1)===&lt;br /&gt;
Bietet einen (gewissen) Schutz vor falschen Konfigurationen und somit entstehenden Endlosschleifen.&lt;br /&gt;
Bei aktiviertem Attribut (1) erkennt das Modul Endlosschleifen eines Devices und beendet diese.&lt;br /&gt;
&lt;br /&gt;
In diesem Fall erfolgt ein Logeintrag und das Device wird per Attribut auf &#039;Disabled&#039; gesetzt.&lt;br /&gt;
Es wird ein letztes Event generiert, auf das reagiert werden kann:&lt;br /&gt;
:&amp;lt;code&amp;gt;2018-05-31 09:39:21 MSwitch &amp;lt;NAME&amp;gt; Safemode: on&amp;lt;/code&amp;gt;&lt;br /&gt;
Im Webinterface erfolgt bei betroffenem Device ein entsprechender Hinweis.&lt;br /&gt;
&lt;br /&gt;
In der Grundkonfiguration ist dieses Attribut nicht gesetzt, es empfiehlt sich aber, bei neuen (komplizierten) Devices, dieses - zumindest anfänglich - zu aktivieren.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Read_Log(0:1)===&lt;br /&gt;
Ermöglicht den Zugriff auf das Logfile als Trigger.&lt;br /&gt;
&lt;br /&gt;
Hier gibt es mehrere Konfigurationsmöglichkeiten:&lt;br /&gt;
* Bei aktiviertem Attribut enthält die Auswahl des Triggerdevices die Option &#039;LOGFILE&#039;. Bei dieser Auswahl werde alle Logeinträge erkannt und in ein internes Event umgewandelt, auf das regiert werden kann.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl &#039;GLOBAL&#039; im &#039;Trigger_Device&#039; wird auf ALLE Events und alle Logeinträge reagiert.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl eines bestimmten Devices im &#039;Trigger_Device&#039; wird auf alle Events  und auf alle Logeinträge des gewählten Devices reagiert. Hier ist zu beachten, dass FHEM mir keine Möglichkeit bietet, wirklich herauszufinden, welches Device denn nun einen Logeintrag generiert hat. D.h., dieses wird vom Vorhandensein des Namens im Logeintrag abhängig gemacht und MSwitch reagiert nur dann auf einen Logeintrag, wenn der Name des Devices in diesem Eintrag vorhanden ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Help(0:1)===&lt;br /&gt;
Schaltet Hilfebuttons zu den einzelnen Eingabefeldern an oder aus.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Comments(0:1)===&lt;br /&gt;
Schaltet Kommentarfelder zu den einzelnen &#039;affected_devices an.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_generate_Events(0:1)===&lt;br /&gt;
Reduziert bei Einstellung &#039;1&#039; die vom MSwitch-Devices erzeugten Events auf ein absolutes Minimum. Insbesondere bei Verwendung von &#039;MSwitch_Read_Log&#039; zu empfehlen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay ===&lt;br /&gt;
Bestimmt die Verzögerungszeit des MSwitches nach FHEM-Start in Sekunden. In diesem Zeitraum reagiert das ??Event??(Red: ist hier &amp;quot;Device&amp;quot; gemeint?) nicht auf Events. Die Vorgabe ist hier zehn Sekunden. Diese wird auch dann angenommen, wenn das Attribut nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Inforoom ===&lt;br /&gt;
Mit diesem Attribut wird die Raumansicht eines mit dem Attribut bestimmten Raumes verändert. Dadurch sollen die wichtigsten Informationen aller MSwitch-Devices auf eine Seite dargestellt werden. Zur Nutzung sollten alle MSwitch-Devices (zusätzlich) in einen Raum sortiert werden und dieser Raum im Attribut eingestellt werden.&lt;br /&gt;
&lt;br /&gt;
Wichtig: Eine Änderung dieses Attributes bewirkt immer eine Änderung dieses Attributes in &#039;&#039;allen&#039;&#039; MSwitch devices: Es muss nur in einem Device gesetzt oder gelöscht werden um alle Devices zu erfassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
MSwitch_Screen_1.png|Raumansicht des Raumes MSwitch mit gesetztem Attribut &#039;MSwitch&#039;&lt;br /&gt;
MSwitch_Screen_2.png|Raumansicht des Raumes MSwitch ohne gesetztes Attribut&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es werden folgende Informationen bereitgestellt:&lt;br /&gt;
* Infobutton zeigt den im Device gespeicherten Textes des Attributes &#039;comment&#039;&lt;br /&gt;
* Device und Events, die das Device triggern&lt;br /&gt;
* Zeiten, zu denen verschiedene Zweige des Devices ausgeführt werden&lt;br /&gt;
* Devices, die durch das MSwitch Device geschaltet werden&lt;br /&gt;
* State des Devices&lt;br /&gt;
&lt;br /&gt;
== Integrierte Funktionen ==&lt;br /&gt;
&lt;br /&gt;
=== Average ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
=== Tendency ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[TEND&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;Mindestwert&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[TEND2:countdown] &amp;gt; 2&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Es wird jeweils der Durchschnitt von 2 Wertepaaren gebildet. In diesem Fall werden die letzten 4 Werte herangezogen.&amp;lt;br&amp;gt;&lt;br /&gt;
Paar 1 = Aktueller und letzter Wert, Paar 2 = Die 2 vorherigen Werte.&amp;lt;br&amp;gt;&lt;br /&gt;
Bei TEND3 werden die letzten 6 Werte zur Paarbildung genutzt.&lt;br /&gt;
&lt;br /&gt;
Mindestwert:&lt;br /&gt;
Der Wertunterschied zwischen den Wertepaaren, der minimal erreicht sein muss, um eine Tendenz zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Rechenzeichen (&amp;gt;&amp;lt;):&lt;br /&gt;
Dieses ist hier nicht als Rechenzeichen zu werten, sonder als Tendenz-Anzeige. ( &amp;lt; es wird nach fallender Tendenz gesucht / &amp;gt; sucht nach steigender Tendenz).&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolgt einmalig bei Erkennung der gesuchten Tendenz.&lt;br /&gt;
Danach erfolgt keine Schaltung mehr, solange bis eine Tendenz-Umkehr erfolgt ist.&lt;br /&gt;
Erst dann erfolgt wieder eine Schaltung bei erneuter Tendenz-Umkehr in gesuchte Richtung.&lt;br /&gt;
&lt;br /&gt;
=== Difference ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[DIFF&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;differenz&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[DIFF2:countdown] &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Gespeicherter Wert (in diesem Fall der vorletzte).&lt;br /&gt;
&lt;br /&gt;
Differenz:&lt;br /&gt;
Geforderter Differenz zwischen aktuellem und vorletztem Wert.&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolg wenn diese Bedingung &#039;wahr&#039; ist.&lt;br /&gt;
&lt;br /&gt;
Folgende Readings werden zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
DIFFERENCE (true/false) - Schaltbedingung erkannt ja/nein&lt;br /&gt;
&lt;br /&gt;
DIFFDIRECTION (up/down) - Richtung der erkannten Bedingung (steigend/fallend)&lt;br /&gt;
&lt;br /&gt;
=== Increase ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
== Tipps, Tricks, Kurzbeispiele ==&lt;br /&gt;
Wird stetig ergänzt.&lt;br /&gt;
&lt;br /&gt;
=== Blinken - Falls nicht im Device vorhanden ===&lt;br /&gt;
[[Datei:MSwitch MSwitchblink.png|center|704px]]&lt;br /&gt;
&amp;lt;br clear=all&amp;gt;&lt;br /&gt;
Lässt ein beliebiges Device 5 mal togglen, mit einem Intervall von 0.5 Sekunden (Blinkzeit somit 2,5 Sekunden)&amp;lt;br&amp;gt;&lt;br /&gt;
Die MSwitchtoggle-Funktion muss per ATTR aktiviert werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Die Repeatfunktion ist nur im Expertmode verfügbar, auch per ATTR einstellbar.&lt;br /&gt;
&lt;br /&gt;
=== Linearschalter ===&lt;br /&gt;
Umsetzung eines Linearschalters mit MSwitch.&lt;br /&gt;
&lt;br /&gt;
Eingang: Beliebiges Reading als numerischer Wert.&lt;br /&gt;
&lt;br /&gt;
Ausgang: Wird entsprechend Linear / oder umgekehrt Linear zum Eingang geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgend die Rawdefinition des MSwitchdevices und zweier Dummys (selbsterklärend)&lt;br /&gt;
&lt;br /&gt;
Alle Devices werden im Raum Lineartest angelegt, die Dummy müssen zuerst angelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod linearausgang dummy&lt;br /&gt;
attr linearausgang room Lineartest&lt;br /&gt;
attr linearausgang setList state:slider,0,1,100&lt;br /&gt;
attr linearausgang webCmd state&lt;br /&gt;
setstate linearausgang state 57&lt;br /&gt;
setstate linearausgang 2018-06-06 18:06:12 state state 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod lineareingang dummy&lt;br /&gt;
attr lineareingang room Lineartest&lt;br /&gt;
attr lineareingang setList state:slider,0,1,15000&lt;br /&gt;
attr lineareingang webCmd state&lt;br /&gt;
setstate lineareingang 6422&lt;br /&gt;
setstate lineareingang 2018-06-06 18:06:12 state 6422&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod Linearschalter MSwitch lineareingang  # linearausgang FreeCmd&lt;br /&gt;
attr Linearschalter MSwitch_Debug 0&lt;br /&gt;
attr Linearschalter MSwitch_Delete_Delays 1&lt;br /&gt;
attr Linearschalter MSwitch_Expert 0&lt;br /&gt;
attr Linearschalter MSwitch_Extensions 0&lt;br /&gt;
attr Linearschalter MSwitch_Help 0&lt;br /&gt;
attr Linearschalter MSwitch_Ignore_Types notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
attr Linearschalter MSwitch_Include_Devicecmds 1&lt;br /&gt;
attr Linearschalter MSwitch_Include_MSwitchcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Include_Webcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Inforoom MSwitch&lt;br /&gt;
attr Linearschalter MSwitch_Lock_Quickedit 1&lt;br /&gt;
attr Linearschalter MSwitch_Mode Notify&lt;br /&gt;
attr Linearschalter room Lineartest&lt;br /&gt;
&lt;br /&gt;
setstate Linearschalter active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:03:50 .Device_Affected FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:04:35 .Device_Affected_Details FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 );;my $emin=0;;my $emax=15000;;my $amin=100;;my $amax=0;;$eingang = $emin if $eingang &amp;lt; $emin;;$eingang = $emax if $eingang &amp;gt; $emax;;my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin;;readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 );;},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter:to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 .Device_Events no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .First_init done&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_on *&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_condition &lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_on no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_time &lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .V_Check V 0.3&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVENT state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTFULL lineareingang:state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART1 lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART2 state&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART3  6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 Exec_cmd set linearausgang state [Linearschalter:to_set]&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 Trigger_device lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 Trigger_log off&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 last_event state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:39:56 state active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 to_set 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
MSwitch -Configfile (bei Bedarf)&lt;br /&gt;
&amp;lt;pre&amp;gt;#V V1.54&lt;br /&gt;
#S .Device_Affected -&amp;gt; FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
#S .Device_Affected_Details -&amp;gt; FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 )[S]my $emin=0[S]my $emax=15000[S]my $amin=100[S]my $amax=0[S]$eingang = $emin if $eingang &amp;lt; $emin[S]$eingang = $emax if $eingang &amp;gt; $emax[S]my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin[S]readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 )[S]},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter.to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
#S .Device_Events -&amp;gt; no_trigger&lt;br /&gt;
#S .First_init -&amp;gt; done&lt;br /&gt;
#S .Trigger_Whitelist -&amp;gt; undef&lt;br /&gt;
#S .Trigger_cmd_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_cmd_on -&amp;gt; *&lt;br /&gt;
#S .Trigger_condition -&amp;gt; &lt;br /&gt;
#S .Trigger_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_on -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_time -&amp;gt; &lt;br /&gt;
#S .V_Check -&amp;gt; V 0.3&lt;br /&gt;
#S Trigger_device -&amp;gt; lineareingang&lt;br /&gt;
#S Trigger_log -&amp;gt; off&lt;br /&gt;
#S last_event -&amp;gt; state: 6422&lt;br /&gt;
#S state -&amp;gt; active&lt;br /&gt;
#A MSwitch_Ignore_Types -&amp;gt; notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
#A MSwitch_Include_MSwitchcmds -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Debug -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Help -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Devicecmds -&amp;gt; 1&lt;br /&gt;
#A MSwitch_Extensions -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Webcmds -&amp;gt; 0&lt;br /&gt;
#A room -&amp;gt; Lineartest&lt;br /&gt;
#A MSwitch_Inforoom -&amp;gt; MSwitch&lt;br /&gt;
#A MSwitch_Expert -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Lock_Quickedit -&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Thread über das Modul im {{Link2Forum|Topic=86199|LinkText=FHEM Forum}}&lt;br /&gt;
* {{Link2Forum|Topic=100119|Message=936495|LinkText=Gäste-WLAN der Fritzbox auswerten und Login per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=86199|Message=930133|LinkText=Schalten von vier Kanälen mit einem MSwitch-Device}}&lt;br /&gt;
* {{Link2Forum|Topic=99219|Message=926652|LinkText=Batterie-Überwachung. 1xTäglich per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=101091|Message=945389|LinkText=Licht (Alarm) in einem bestimmten Zeitraum schalten}}&lt;br /&gt;
* {{Link2Forum|Topic=100949|Message=944284|LinkText=Über Dummy-Schalter ein Timer (EIN/AUS) aktivieren}}&lt;br /&gt;
* {{Link2Forum|Topic=103083|Message=967710|LinkText=Ladezeit von Akku ermitteln u. Steckdose entsprechend schalten}}&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31479</id>
		<title>MSwitch</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31479"/>
		<updated>2019-11-01T20:01:44Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* MSwitch_Debug (0:1:2:3:4) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[MSwitch]] ist ein Hilfsmodul, welches das Event- und/oder zeitgesteuerte Schalten von mehreren Devices oder das Ausführen von benutzerdefinierten Befehlssequenzen erlaubt.&lt;br /&gt;
&lt;br /&gt;
Die Stärke bzw. das Unterscheidungsmerkmal dieses Moduls liegt in der Konfigurierbarkeit über ein Webinterface. Diese Konfiguration kann jederzeit geändert oder erweitert werden. &lt;br /&gt;
&lt;br /&gt;
Byte09: &#039;&#039;Die Grundidee zu MSwitch kam mir, weil ich bei der Arbeit mit FHEM für meinen Geschmack zu viele Module für die verschiedenen Aufgaben brauchte - zu allem Überfluss alle mit unterschiedlicher Syntax. Zwar ist DOIF hiervon ausgenommen (da hiermit wohl auch fast jede Aufgabe lösbar ist), aber ich konnte mich leider nicht daran gewöhnen und somit wurde jedes DOIF für mich zu einem echten Projekt. Was ich wollte war ein Modul, mit dem ich alles erledigen kann. Daher entschloss ich mich schon nach fast einem knappen Jahr FHEM-Nutzung mein eigenes Modul zu schreiben, welches diese Anforderung erfüllt. MSwitch beinhaltet die Funktionalität aller bisherigen Hilfsmodule wie z.B. Notify, Doif, Watchdog, Dummy,( ab Modulversion 2.2 auch Sequenz ) es lassen sich all deren Funktionen umsetzen.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;MSwitch wird permanent - vorrangig nach meinen Bedürfnissen - weiterentwickelt, gerne nehme ich aber auch Anregungen von anderen Nutzern auf.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=MSwitch&lt;br /&gt;
|ModType=h&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=98_MSwitch.pm&lt;br /&gt;
|ModOwner=Byte09}}&lt;br /&gt;
&lt;br /&gt;
== Grundsätzliche Überlegungen ==&lt;br /&gt;
Um das Modul zu nutzen, muss man zuerst folgende Fragen beantworten:&lt;br /&gt;
&lt;br /&gt;
* Welches Gerät soll auslösen oder zu welcher Zeit soll eine Auslösung erfolgen.&lt;br /&gt;
: Dies ist der Trigger. Jedes Event aus dem Eventmonitor kann als Trigger dienen. Will man mehrere Geräte als gleichzeitige Auslöser betreiben, so muss das Device GLOBAL gewählt und die entsprechenden Geräte angegeben werden (dies erzeugt höhere Systemlast und ist nur im Expert-Modus verfügbar). Weiterhin kann auch zu fest definierten Zeiten, Zufallszeiten oder Intervallen, unabhängig von einem Trigger, geschaltet werden; auch eine Kombination beider Varianten ist möglich. Diese Einstellungen erfolgen im ersten Teil des Webinterfaces.&lt;br /&gt;
&lt;br /&gt;
* Welche Bedingungen sollen bei Auslösung erfüllt sein?&lt;br /&gt;
: Wenn diese Bedingungen erfüllt sind, werden Kommandos ausgelöst. Die Bedingungen werden im zweiten Teil des Webinterfaces eingegeben. Dabei unterscheidet das Modul zwischen zwei Kommando-Kanälen (cmd1 und cmd2) und den dazugehörigen Geräten.&lt;br /&gt;
&lt;br /&gt;
* Welche Kommandos sollen ausgelöst werden?&lt;br /&gt;
: Im dritten Teil des Webinterfaces werden dann die konkreten Kommandos eingegeben. Typischerweise wählt man dabei aus einer Liste der Kommandos aus, die die zugehörigen Geräte insgesamt aufweisen (also so, wie man auf den Geräteseiten selber Kommandos auswählt). Es gibt zudem ein so genanntes FreeCmd, das ein Geräteunabhängiges Kommando zulässt, beispielsweise reinen Perl-Code.&lt;br /&gt;
&lt;br /&gt;
* Welche weiteren Bedingungen sollen noch gelten?&lt;br /&gt;
: Hier sind Ereignisgesteuerte wie auch Zeitgesteuerte Bedingungen möglich. Diese Bedingungen werden auch in dem dritten Teil des Webinterfaces eingetragen. So sind Verzögerungen und Wiederholungen und weitere Bedingungen möglich.&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen, Installation und Grundbefehle ==&lt;br /&gt;
Das MSwitch-Modul ist ohne weitere Voraussetzungen nutzbar und wird derzeit in der Version 2.08 über FHEM Update verteilt. &lt;br /&gt;
&lt;br /&gt;
=== Definition und Einrichtung ===&lt;br /&gt;
Mit Hilfe von MSwitch kann man mehrere Devices gleichzeitig schalten. Diese Schaltungen befinden sich in zwei möglichen Zweigen bei MSwitch. Dabei unterscheidet man im Modul zwischen den beiden Kommandos cmd1 und cmd2. Die zu einem Kommando gehörenden Geräte werden wir auch Zweig nennen. Die einzelnen Devices jedes Zweiges können mit weiteren Schaltbedingungen versehen werden (zeit- oder ereignisgesteuert). &lt;br /&gt;
&lt;br /&gt;
Folgende Möglichkeiten zum definieren des MSwitch Devices stehen zur Verfügung:&lt;br /&gt;
:&amp;lt;code&amp;gt;define &amp;lt;name&amp;gt; MSwitch&amp;lt;/code&amp;gt;&lt;br /&gt;
Es wird ein leeres Device angelegt, das dann komplett über das Webinterface konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das define eines MSwitch Devices generiert lediglich eine &#039;leere Hülle&#039;. Alle relevante Einstellungen werden in Readings und/oder Hashes gespeichert. Daher stehen relevanten Daten &#039;&#039;nicht&#039;&#039; in der fhem.cfg! Vielmehr finden sich diese Daten in der Datei fhem.save (die Speicherung erfolgt durch den Befehl Fhemsave).&lt;br /&gt;
&lt;br /&gt;
=== set-Befehle ===&lt;br /&gt;
Es sind derzeit die folgenden set-Befehle implementiert.&lt;br /&gt;
&lt;br /&gt;
==== set active ====&lt;br /&gt;
Setzt das Device in den Status &#039;active&#039;.&lt;br /&gt;
&lt;br /&gt;
==== set inactive ====&lt;br /&gt;
Setzt das Device in den Status &#039;inactive&#039;, es werden keine Befehle mehr ausgeführt. Dieser Status entspricht dem Attribut &#039;disable&#039;, ist aber nicht mit dem roten Fragezeichen (fhem save) verbunden.&lt;br /&gt;
&lt;br /&gt;
==== set on/off [&amp;lt;parameter&amp;gt;]====&lt;br /&gt;
Setzt das Device in den Status &#039;on&#039; oder &#039;off&#039;. Alle Befehle der &#039;on/off-Zweige&#039; werden ausgeführt.&lt;br /&gt;
Optional kann den Befehlen &#039;on&#039; und &#039;off&#039; ein weiterer Parameter mit übergeben werden. Dieser wird im Reading &#039;Parameter&#039; hinterlegt und es kann sofort in &#039;Freecmds&#039; oder &#039;Conditions&#039; darauf zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
==== set reload_timer ====&lt;br /&gt;
Alle gesetzten Timer werden gelöscht und neu berechnet.&lt;br /&gt;
&lt;br /&gt;
==== set change_renamed &amp;lt;oldname&amp;gt; &amp;lt;newname&amp;gt; ====&lt;br /&gt;
Sollten sich Devicenammen im ausführenden Teil geändert habe (affected Devices, Conditions, etc.) so kann das MSwitch mit diesem Befehl angepasst werden, ohne alle Einstellungen neu einstellen zu müssen.&lt;br /&gt;
&lt;br /&gt;
==== set exec_cmd1 / set exec_cmd1 ID [&amp;lt;ID&amp;gt;] ====&lt;br /&gt;
Bewirkt das sofortige Ausführen des entsprechenden Befehlszweiges. Bei Angabe einer ID werden nur die Befehle mit der entsprechenden ID ausgeführt.&lt;br /&gt;
&lt;br /&gt;
==== set MSwitch_backup ====&lt;br /&gt;
Erstellt eine Backup-Datei aller MSwitch Devices unter ./fhem/MSwitch_backup.cfg.&lt;br /&gt;
&lt;br /&gt;
Daten dieser Datei können im Bedarfsfall für einzelne oder gleichzeitig alle MSwitch Devices wieder zurückgespielt (hergestellt) werden.&lt;br /&gt;
&lt;br /&gt;
==== set del_delays ====&lt;br /&gt;
Löscht alle anstehenden, verzögerten Befehle (delays).&lt;br /&gt;
&lt;br /&gt;
==== set reset_cmd_count:1,2 ====&lt;br /&gt;
Löscht das entsprechende EVT_CMD_COUNT - Reading (entspricht Rückstellung auf &#039;0&#039;).&lt;br /&gt;
&lt;br /&gt;
==== set fakeevent [&amp;lt;device&amp;gt;]:&amp;lt;reading&amp;gt;:&amp;lt;arg&amp;gt; ====&lt;br /&gt;
Beispiel: &amp;lt;device&amp;gt; fakeevent state:on&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ob der Name (&amp;lt;device&amp;gt;) angegeben werden muss, oder nicht, ist abhängig davon, ob auf ein einzelnes Device, oder GLOBAL getriggert wird. Bei GLOBALEN Triggern muss das Device mit angegeben werden. Wird auf ein Device getriggert, so wird das Device automatisch gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit diesem Befehl kann das MSwitch Device neu getriggert werden, indem hier ein Event &#039;gefaked&#039; wird. Das MSwitch Device reagiert dann so, als wäre dieses Event vom getriggerten Gerät generiert worden. &lt;br /&gt;
&lt;br /&gt;
Dieses kann nötig sein, um z.B. einen Watchdog zu realisieren, in dem es nötig ist, dass sich das MSwitch Device mit einem bestimmten Event selber neu triggert - ggf. mit einem entsprechenden Delay (affected Device muss dafür u.A. des MSwitch Device selber sein).&lt;br /&gt;
&lt;br /&gt;
Es wird hierbei KEIN echtes Event generiert welches das System beeinflusst, sondern ausschließlich ein MSwitch-Interner Befehl umgesetzt!&lt;br /&gt;
&lt;br /&gt;
Bei dem Einsatz dieser Möglichkeit sollte das Attribut &#039;MSwitch_Safemode&#039; UNBEDINGT aktiviert sein, da &#039;Experimente&#039; hier schnell in einer Endlosschleife enden können, die nur durch ein Reboot unterbrochen werden kann. &lt;br /&gt;
&lt;br /&gt;
Ggf. werde ich hier sogar eine entsprechende Änderung vornehmen, dass dieser Befehl nur zur Verfügung steht, wenn Safemode aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
=== get-Befehle ===&lt;br /&gt;
==== get show_timer [&amp;lt;show&amp;gt;&amp;lt;delete&amp;gt;] ====&lt;br /&gt;
;Show&lt;br /&gt;
:Zeigt alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren.&lt;br /&gt;
;Delete&lt;br /&gt;
:Löscht alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren. Schaltbefehle basierend auf rein zeitabhängigen Angaben werden neu berechnet und gesetzt.&lt;br /&gt;
&lt;br /&gt;
==== get restore_MSwitch_data [&amp;lt;this_device&amp;gt;&amp;lt;all_devices&amp;gt;] ====&lt;br /&gt;
;this_device&lt;br /&gt;
:Stellt die Daten des Devices aus der Backupdatei wieder her, sofern diese in der Backupdatei gefunden werden (gesucht wird hier nach dem Namen des Devices).&lt;br /&gt;
;all_devices&lt;br /&gt;
:Stellt die Daten aller MSwitch Devices wieder her, sofern diese in der Backupdatei vorhanden sind. Diese Aktion kann einige Zeit in Anspruch nehmen und wird daher im Hintergrund (nonblocking) ausgeführt. Nach Beendigung erfolgt eine Benachrichtigung.&lt;br /&gt;
&lt;br /&gt;
Die Devices sind nach einem Restore funktionsfähig. Empfohlen wird ein Neustart von FHEM.&lt;br /&gt;
&lt;br /&gt;
==== get_config ==== &lt;br /&gt;
Zeigt die Konfigurationsdatei des MSwitchdevices an; diese kann in dem Fenster editiert werden. Das sollte nur von erfahrenen Usern getan werden! Im Normalfall sollte das Device nur über die Weboberfläche konfiguriert werden und eine falsche Konfiguration kann hier zu einem FHEM Absturz führen.&lt;br /&gt;
&lt;br /&gt;
==== get_support_info ==== &lt;br /&gt;
Öffnet ein Fenster mit einer formatierten Ansicht aller Einstellungen des Devices. Bei Supportanfragen sollte dieses immer mit geposted werden.&lt;br /&gt;
&lt;br /&gt;
==== get_MSwitch_preconf ====&lt;br /&gt;
Lädt vorkonfigurierte MSwitch-Devices. Diese Option ist nur dann vorhanden, wenn das Aktualisieren dieser vorkonfigurierten Devices im FHEM Update aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
Diese kann durch ein einmaliges Update erfolgen mit:&lt;br /&gt;
:&amp;lt;code&amp;gt;update all https://raw.githubusercontent.com/Byte009/MSwitch_Addons/master/controls_mswitchaddons.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Webinterface ==&lt;br /&gt;
MSwitch wird im Wesentlichen über das Webinterface eingerichtet. Wählt man das folgende Attribut&lt;br /&gt;
:&amp;lt;code&amp;gt;attr &amp;lt;name&amp;gt; MSwitch_Help 1&amp;lt;/code&amp;gt;&lt;br /&gt;
so wird im Modul selber eine sehr umfangreiche Hilfe angezeigt. Über das gesamte Webinterface hinweg erscheinen kleine Fragezeichen, die man anklicken kann und die beschreiben, was in dem jeweiligen Textfeld sinnvollerweise einzugeben ist bzw. was das Modul an dieser Stelle erwartet.&lt;br /&gt;
&lt;br /&gt;
Das Webinterface besteht aus vier Teilen. Änderungen in jedem Abschnitt müssen in dem jeweiligen Teil bestätigt werden und auch nur diese werden gespeichert. Bevor ein weiterer Teil bearbeitet wird, sollten Änderungen gespeichert werden, sie gehen sonst verloren.&lt;br /&gt;
&lt;br /&gt;
=== Trigger device/time ===&lt;br /&gt;
==== Trigger Device ====&lt;br /&gt;
In diesem Feld wird das Device ausgewählt, dessen Events eine Aktion auslösen sollen. Dazu werden alle verfügbaren Devices in einem Dropdownfeld angeboten.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es eine Auswahl &#039;GLOBAL&#039;, wenn das Attribut &#039;MSwitch_Expert&#039; gesetzt ist. Bei Auswahl dieser Option werden &#039;&#039;&#039;alle&#039;&#039;&#039; von FHEM generierten Events durch das MSwitch Device weiterverarbeitet, eine weitere Begrenzung der aktivierenden Events kann (und sollte) dann in einem folgenden Eingabefeld erfolgen, um die Systemlast zu reduzieren.&lt;br /&gt;
&lt;br /&gt;
==== Trigger Device Global Whitelist ====&lt;br /&gt;
Dieses Feld ist nur verfügbar, wenn als Trigger &#039;GLOBAL&#039; gewählt wurde.&lt;br /&gt;
&lt;br /&gt;
Hier kann die Liste eingehender Events weiter eingeschränkt werden. Es handelt sich um eine Whitelist, d.h., wenn es keine Einträge gibt, werden Events aller Devices verarbeitet. Sobald ein oder mehrere Einträge gemacht werden, werden nur noch Events der hier benannten Devices verarbeitet. Als Angabe können hier Devices benannt werden oder ganze DeviceTypen (z.B. TYPE=FS20). Mehrere Angaben sind durch Komma zu trennen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:MSwitchWebinterface1.png|400px|thumb|right|Webinterface, oben]]&lt;br /&gt;
Im gezeigten Beispiel wurde GLOBAL gewählt, weil nicht ein einzelnes Device, sondern eine Kombination aus zwei Geräten auslösen soll. Es werden also alle Ereignisse betrachtet, wobei die Whitelist dann auf die Devices Schlafzimmer (ein Temperaturmessgerät) und Schlafzimmerfenster (ein [[HM-Sec-SCo Tür-Fensterkontakt, optisch|optischer Kontakt]]) einschränkt. &lt;br /&gt;
&lt;br /&gt;
==== Trigger time ==== &lt;br /&gt;
Es besteht die Möglichkeit, das Modul (neben den Events) zu festen Zeiten auszulösen. Dann wären in die leer stehenden Zeilen bei &amp;quot;at&amp;quot; entsprechende Termine einzutragen. Zeitangaben erfolgen durch [STUNDEN:MINUTEN|TAGE], wobei die Tage von 1-7 gezählt werden (1 steht für Montag, 7 für Sonntag usw.). &lt;br /&gt;
Mehrere Zeitvorgaben können direkt aneinandergereiht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [17:00|1][18:30|23] den Trigger montags um 17 Uhr auslösen und dienstags sowie mittwochs um 18:30 Uhr.&lt;br /&gt;
Bei [00:10*20:00-21:00] würde der Schaltbefehl von 21 Uhr bis 21 Uhr alle 10 Minuten ausgeführt. Bei [?20:00-21:00] würde der Schaltbefehl zu einem zufälligen Zeitpunkt zwischen 20 und 21 Uhr ausgeführt.  [20:00|$we] bedeutet, dass nur am Wochenende um 20:00 geschaltet wird.&lt;br /&gt;
&lt;br /&gt;
==== Trigger conditions ====&lt;br /&gt;
Hier kann die Angabe von Bedingungen erfolgen, die zusätzlich zu dem triggernden Device erfüllt sein müssen.&lt;br /&gt;
Diese Bedingungen sind eng an DOIF-Syntax angelehnt. Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich.&lt;br /&gt;
&lt;br /&gt;
Wird in diesem Feld keine Angabe gemacht, so erfolgt der Schaltvorgang nur durch das triggernde Device ohne weitere Bedingungen.&lt;br /&gt;
&lt;br /&gt;
;Zeitabhängigkeit&lt;br /&gt;
:[19:10-23:00] - Trigger des Devices erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
;Readingabhängige Trigger&lt;br /&gt;
:[Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Trigger des Device erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
:Werden Readings mit Strings abgefragt (on,off,etc.), ist statt des Gleichheitszeichens &amp;quot;=&amp;quot; der Operator &amp;quot;eq&amp;quot; zu nutzen, der String muss in Anführungszeichen &amp;quot;&amp;quot; gesetzt werden.&lt;br /&gt;
;mehrere Beispiele&lt;br /&gt;
:[19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
:[19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
:[10:00-11:00|13] - schaltet Montag und Mittwoch zwischen 10 Uhr und 11 Uhr.&lt;br /&gt;
:[{ sunset() }-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
:{ !$we } löst den Schaltvorgang nur Werktagen an aus.&lt;br /&gt;
:{ $we } löst den Schaltvorgang nur an Wochenenden, Feiertagen aus.&lt;br /&gt;
&lt;br /&gt;
Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (beispielsweise würde dann am Mittwoch noch der Schaltvorgang erfolgen, obwohl als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
Bedingungen in diesem Feld gelten nur für auslösende Trigger eines Devices und haben keinen Einfluss auf zeitgesteuerte Auslöser.&lt;br /&gt;
&lt;br /&gt;
=== Trigger details ===&lt;br /&gt;
[[Datei:MSwitchWebinterface2.png|600px|thumb|right|Webinterface, Mitte]]&lt;br /&gt;
Während im obigen Feld das Device ausgewählt  werden konnte, wird hier das Ereignis festgelegt. Das Eingabefeld besteht aus mehreren Einzelfeldern.&lt;br /&gt;
&lt;br /&gt;
Im abgebildeten Fall wird cmd1 ausgelöst, wenn der Zustand des Schlafzimmerfenster-Sensors meldet, dass das Fenster offen ist. Cmd2 wird ausgelöst, wenn die Temperatur des Schlafzimmersensors unter einen bestimmten Wert fallen wird.&lt;br /&gt;
&lt;br /&gt;
==== execute &#039;cmd1/cmd2&#039;  ====&lt;br /&gt;
Hier kann  aus einer vorbelegten Dropdownliste ausgewählt werden, welches ankommende Event den entsprechenden Befehlszweig auslösen soll. In dieser Liste werden bei entsprechender Einstellung alle ankommenden Events eines vorher definierten Devices gespeichert. In einem weiteren Feld (siehe unten) können Events manuell zugefügt werden.&lt;br /&gt;
&lt;br /&gt;
==== Save incomming events ====&lt;br /&gt;
Bei Aktivierung dieser Option werden alle ankommenden Events des oben definierten Devices (oder Global) gespeichert und in entsprechenden Dropdownlisten angeboten.&lt;br /&gt;
&lt;br /&gt;
Da hier doch erhebliche Datenmengen anfallen können (je nach Device) wird empfohlen, diese Option nach der Konfiguration des Devices zu deaktivieren.&lt;br /&gt;
&lt;br /&gt;
==== add event ====&lt;br /&gt;
Hier besteht die Möglichkeit, unabhängig von der Option, ankommende Events automatisch zu speichern. Manuell Events anzulegen, die in den Dropdownliste zur Auswahl angeboten werden, ohne das entsprechendes Event erst vom Device geliefert werden muss.&lt;br /&gt;
&lt;br /&gt;
Es können mehrere Events gleichzeitig eingegeben werden, eine Trennung erfolgt durch &amp;quot; , &amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Hier ist zu unterscheiden, ob das gewählte triggernde Device ein einfaches Device ist oder ob der Trigger &#039;GLOBAL&#039; ist.&lt;br /&gt;
Bei triggernden Devices können Events in folgendem Formaten zugefügt werden:&lt;br /&gt;
&lt;br /&gt;
- *                                                    - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:wert   (z.b. state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:*      (z.b. state:* )                       - Aktion erfolgt auf die Events &amp;quot;state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:(wert1/wert2/wert3) (z.b. state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;state:left&amp;quot; oder &amp;quot;state:right&amp;quot; etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Falls auf &#039;GLOBALE&#039; Events getriggert wird, muss das auslösende Device vorangestellt werden:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
- *                                                           - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:wert   (z.b. device:state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;device:state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:*      (z.b. device:state:* )                       - Aktion erfolgt auf die Events &amp;quot;device:state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:(wert1/wert2/wert3) (z.b. device:state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;device:state:left&amp;quot; oder &amp;quot;devicestate:right&amp;quot; etc.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Device kann auch hier gegen &amp;quot;*&amp;quot; ersetzt werden (*:state:on). In diesem Fall erfolgt eine Aktion auf alle Events die z.B. &amp;quot;state:on&amp;quot; enthalten, egal welches Device triggert.&lt;br /&gt;
&lt;br /&gt;
==== test event ====&lt;br /&gt;
Dieses Feld wird angeboten, wenn entsprechende vom Triggerdevice gelieferte Events gespeichert wurden.&lt;br /&gt;
&lt;br /&gt;
Durch Auslösen dieser Funktion wird das Event simuliert und entsprechende definierte Aktionen ausgelöst. Diese Funktion dient ausschließlich zum Testen der eingestellten Konfiguration. Alle entsprechenden Befehle werden ausgeführt, als würde das Event real eintreffen.&lt;br /&gt;
&lt;br /&gt;
==== apply filter to saved events ====&lt;br /&gt;
Beschreibung folgt&lt;br /&gt;
&lt;br /&gt;
==== clear saved event ====&lt;br /&gt;
Es werden alle gespeicherten Events gelöscht.&lt;br /&gt;
&lt;br /&gt;
Ausnahme: Events, die als Trigger eingestellt sind, bleiben erhalten.&lt;br /&gt;
&lt;br /&gt;
=== Affected devices ===&lt;br /&gt;
[[Datei:MSwitch_Screen_5.png|mini|rechts|affected devices]]&lt;br /&gt;
Dieser Abschnitt beinhaltet die Auswahl der Devices, die auf ein Event reagieren sollen.&lt;br /&gt;
&lt;br /&gt;
In dem Auswahlfeld werden alle Devices angeboten, die eines der folgenden Kriterien erfüllen:&lt;br /&gt;
# Die Abfrage &amp;quot;set Device ?&amp;quot; liefert einen Befehlssatz&lt;br /&gt;
# Das Attribut &#039;webcmd&#039; des Devices enthält Einträge&lt;br /&gt;
# Das Attribut &#039;MSwitch_Activate_MSwitchcmds&#039; ist aktiviert und das Attribut &#039;MSwitchcmds&#039; des betreffenden Devices enthält einen Befehlssatz&lt;br /&gt;
&lt;br /&gt;
Einzige Ausnahme ist der erste Listeneintrag &#039;FreeCMD&#039;. Die Auswahl dieses Eintrages bietet später die Möglichkeit Befehle auszuführen, die nicht an ein Device gebunden sind. Der Code in einem FreeCmd kann entweder reiner FHEM-Code sein ( set device on ) oder reiner Perl-Code. Wenn es sich um reinen Perl-Code handelt, ist dieser in geschweifte Klammen zu setzen { Perl-Code }.&lt;br /&gt;
&lt;br /&gt;
=== Device actions ===&lt;br /&gt;
[[Datei:Webinterface3.png|mini|rechts|device_actions]]&lt;br /&gt;
Hier stellt man die auszuführenden Aktionen der eingestellten Devices ein. Im ersten Abschnitt oben befindet sich ein FreeCmd, mit dem beliebige Kommandos eingetragen werden können. Im abgebildeten Beispiel ist dies sogar selbst definierter Perl-Code (die Funktion DebianMail sendet eine Mail). &lt;br /&gt;
&lt;br /&gt;
==== MSwitch cmd1/cmd2:  ====&lt;br /&gt;
Man wählt den Befehl aus dem betreffenden Device aus. Bei freien Textfeldern (wie im Fall des FreeCmd) wird der Befehl eingegeben.&lt;br /&gt;
&lt;br /&gt;
Es werden alle verfügbaren Befehle des Devices zur Auswahl angeboten. Je nach Attribut-Einstellungen werden Einträge aus entsprechenden &#039;webcmds&amp;quot; oder &#039;MSwitchcmds&#039; einbezogen. In Abhängigkeit des Befehls stehen unter Umständen weitere Felder oder Widgets zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
05.04.2018 NEU: Auswahlfeld &#039;MSwitchtoggle&#039; -&amp;gt; Beschreibung wird noch ergänzt !&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 condition  ====&lt;br /&gt;
Mit diesem Feld kann die Ausführung des Befehls von weiteren Bedingungen abhängig gemacht werden. Bei der Abfrage von Readings nach Strings (on, off, etc.) ist statt &amp;quot;=&amp;quot; &amp;quot;eq&amp;quot; zu nutzen und der String muss in &amp;quot;x&amp;quot; gesetzt werden. Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
#Zeitabhängiges schalten: [19:10-23:00] - Schaltbefehl erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
#Readingabhängiges schalten [Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Schaltbefehl erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
&lt;br /&gt;
Soll nur an bestimmten Wochentagen geschaltet werden, muss eine Zeitangabe gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [10:00-11:00|13] den Schaltvorgang nur Montag und Mittwoch zwischen 10 Uhr und 11 Uhr auslösen. Hierbei zählen die Wochentage von 1-7 für Montag-Sonntag.&lt;br /&gt;
&lt;br /&gt;
Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich:&lt;br /&gt;
* [19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
* [19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
* [{sunset()}-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
* { !$we } löst den Schaltvorgang nur Werktagen aus&lt;br /&gt;
* { $we } löst den Schaltvorgang nur Wochenenden, Feiertagen aus&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung:&#039;&#039;&#039; Bei Anwendung der geschweiften Klammern zur Einleitung eines Perl Ausdrucks ist unbedingt auf die Leerzeichen hinter und vor der Klammer zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (zum Beispiel würde auch am Mittwoch noch der Schaltvorgang erfolgen, wenn als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
; $EVENT:&lt;br /&gt;
: Die Variable EVENT enthält den auslösenden Trigger, d.h. es kann eine Reaktion in direkter Abhängigkeit zum auslösenden Trigger erfolgen.&lt;br /&gt;
&lt;br /&gt;
[$EVENT] eq &amp;quot;state:on&amp;quot; würde den Kommandozweig nur dann ausführen, wenn der auslösende Trigger &amp;quot;state:on&amp;quot; war. Wichtig ist dieses, wenn bei den Triggerdetails nicht schon auf ein bestimmtes Event getriggert wird, sondern hier durch die Nutzung eines Wildcards (*) auf alle Events getriggert wird, oder auf alle Events eines Readings z.B. (state:*).&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 delay  ====&lt;br /&gt;
Ein Eintrag in diesem Feld führt zur verzögerten Ausführung des Befehls nach Eintreffen des Events. Dabei kann der Befehl ohne weitere Prüfung der Bedingung ausgelöst werden. Es ist aber auch möglich, dass die Bedingung bei Ausführung erneut geprüft wird. Die Zeitangabe muss im Format hh:mm:ss vorliegen.&lt;br /&gt;
&lt;br /&gt;
Statt einer unmittelbaren Zeitangabe kann hier auch ein Verweis auf ein Reading eines Devices erfolgen :&amp;lt;br&amp;gt;&lt;br /&gt;
[NAME.reading] des Devices -&amp;gt;z.B. [dummy.state]&lt;br /&gt;
&lt;br /&gt;
==== add action  ====&lt;br /&gt;
Mit diesem Button kann ein weiteres Eingabefeld für das entsprechende Device angelegt werden, um z.B. einen weiteren Befehl (ggf.) zeitverzögert auszuführen.&lt;br /&gt;
&lt;br /&gt;
==== delete this action  ====&lt;br /&gt;
Mit diesem Button wird der entsprechende Befehl für das Device gelöscht.&lt;br /&gt;
&lt;br /&gt;
==== check condition  ====&lt;br /&gt;
[[Datei:MSwitch_Screen_7.png|mini|rechts|check]]&lt;br /&gt;
Die angegebenen &#039;conditions&#039; werden in Zusammenhang mit ggf. ausgewählten Devices auf Syntax und Ergebnis geprüft. Es erfolgt eine Ausgabe des Prüfungsergebnisses.&lt;br /&gt;
&lt;br /&gt;
==== Repeat und Repeatdelay ====&lt;br /&gt;
Man kann mehrfache Wiederholungen erzwingen. Repeat gibt dabei an, wie oft das Kommando wiederholt wird (Anzahl). Repeatdelay gibt an, wie viel Sekunden zwischen einzelnen Wiederholungen liegen sollen.&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Folgende Attribute stehen zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Debug (0:1:2:3:4) ===&lt;br /&gt;
0 - Abgeschaltet&amp;lt;br&amp;gt;&lt;br /&gt;
1 - Schaltet Felder zum testen der Conditionstrings etc. an&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Alle ausgehenden Befehle werden nur simuliert und nicht ausgeführt. Es erfolgt eine Protokollierung in einer separaten Datei. Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Es erfolgt eine Protokollierung in einer separaten Datei. Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
4 - erweiterte Debug-Funktion (nur für Entwicklung - wechselnde Funktion )&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Expert (0:1) ===&lt;br /&gt;
In der Liste der möglichen Trigger erscheint das Selectfeld &#039;GLOBAL&#039;. Dieses ermöglicht das Setzen eines Triggers auf alle Events und damit nicht nur auf einzelne Devices. In einem weiteren Feld kann eine weitere Selektion der triggernden Events erfolgen.&lt;br /&gt;
&lt;br /&gt;
Es stehen weitere Felder &#039;Repeats&#039; und &#039;Repeatdelay in sec&#039; zur Verfügung. Eine hier getätigte Einstellung bewirkt X-fache Wiederholung von gesetzten Befehlen im Abstand der gesetzten Sekunden.&lt;br /&gt;
&lt;br /&gt;
Weiterhin kann über das Auswahlfeld &#039;priotity&#039; bei jedem &#039;affectes device&#039; die Reihenfolge beim abarbeiten der Befehle beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequenz &amp;lt;Suchmuster&amp;gt; ===&lt;br /&gt;
In diesem Attribut können ein oder mehrere Suchmuster angegeben werden ,die eine Schaltsequenz darstellen und vom Device erkannt werden.&lt;br /&gt;
&lt;br /&gt;
Die Angabe muss folgende Syntax haben:&lt;br /&gt;
:&amp;lt;code&amp;gt;Device1:reading1:event1 Device1:reading1:event1-2 Device1:reading1:event1-3/..../....&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mehrere Suchmuster müssen durch &amp;quot;/&amp;quot; getrennt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
:&amp;lt;code&amp;gt;Dummy:state:on Dummy:state:off Dummy:state:on&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erkennt das Device dieses Suchmuster in den Schaltvorgängen des Devices (Dummy), wird das Reading &amp;quot;SEQUENCE&amp;quot; auf &amp;quot;match&amp;quot; gesetzt, das Reading &amp;quot;SEQUENCE_NUMBER&amp;quot; auf die Nummer der gefundenen Sequenz, wenn es mehrere Suchmuster gibt. Beide Readings können in den &amp;quot;Conditions&amp;quot; eines Schaltbefehles abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequence_time &amp;lt;Zeit in Sekunden&amp;gt; ===&lt;br /&gt;
Beinhaltet die Zeit in Sekunden, die es dauern darf, um eine Sequenz vollständig auszuführen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Extensions (0:1) ===&lt;br /&gt;
Es wird eine zusätzliche Schaltoption &#039;MSwitchToggle&#039; in den Geräten angeboten. Diese kann genutzt werden, wenn zuschaltende Geräte eine Togglefunktion nicht von Haus aus anbieten.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe muss in folgendem Format gemacht werden:&lt;br /&gt;
:&amp;lt;code&amp;gt;on/off/state/suchmuster1/suchmuster2&amp;lt;/code&amp;gt;, wobei die letzten drei Angaben optional sind.&lt;br /&gt;
&lt;br /&gt;
Funktion: Bei Ausführung des Befehls wird das Gerät &#039;on&#039; oder &#039;off&#039; geschaltet (on/off), Voraussetzung ist, dass der &#039;state&#039; dieses Gerätes auch den &#039;state on&#039; oder &#039;off&#039; annimmt. Sollte dieses nicht der Fall sein, so kann mit dem Feld &#039;state&#039; angegeben werden, in welchem Reading der aktuelle Status vorkommt und wie dieser lautet (suchmuster1/suchmuster2). Dieses &#039;state&#039; kann mehrere Angaben enthalten, das Vorkommen der Suchmuster ist aber Voraussetzung.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Delete_Delays (0:1) ===&lt;br /&gt;
Bewirkt das Löschen aller anstehende Timer (Delays) bei dem Auftreten eines erneuten, passenden Events. Bei der Option &#039;0&#039; bleiben bereits gesetzte Delays aus einem vorherigen, getriggertem Event erhalten und werden ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1)&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Devicecmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz liefern (bei Abfrage set DEVICE ?).&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Webcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut Webcmd hinterlegt haben. Die in Webcmd hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten.&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Activate_MSwitchcmds (0:1) ===&lt;br /&gt;
Fügt jedem vorhandenen Device as Attribut &#039;MSwitchcmd&#039; hinzu.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_MSwitchcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut MSwitchcmds hinterlegt haben. Die in MSwitchcmds hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten. Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr Angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Lock_Quickedit (0:1) ===&lt;br /&gt;
Voreinstellung für die Auswahlliste &#039;Affected Devices&#039;. Bei der Option (1) ist diese voreingestellt gesperrt und kann nur über einen zusätzlichen Button geändert werden. Da es sich hier um ein Feld mit der Möglichkeit einer Mehrfacheingabe handelt handelt ist die Voreinstellung 1, um versehentliche nicht gewünschte Änderungen zu vermeiden (Auswahl einer Option ohne &#039;Strg&#039; bewirkt das löschen aller bereits gesetzten Optionen).&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay (0:10:20:30:60) ===&lt;br /&gt;
Diese Einstellung beeinflusst den Start von MSwitch nach einem FHEM Start. MSwitch ignoriert für die angegebene Zeit in Sekunden alle eingehenden Events um u.a. Startverzögerungen zu vermeiden. Bei nicht gesetztem Attribut gilt hier eine Zeit von 30 Sekunden. Diese sollte auch nur in Ausnahmefällen bzw. bei besonderem Bedarf geändert werden.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (30).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Ignore_Types ===&lt;br /&gt;
Beinhaltet eine Liste von Device&#039;&#039;typen&#039;&#039;, die in den Auswahllisten &#039;&#039;nicht&#039;&#039; dargestellt werden. Hier ist es sinnvoll, Devicetypen einzutragen, die in aller Regel nicht geschaltet werden oder nicht geschaltet werden können, um die Auswahllisten übersichtlicher zu halten. Einzelne Devicetypen sind durch Leerzeichen zu trennen.&lt;br /&gt;
&lt;br /&gt;
Voreinstellung: notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe kann hier in 2 Arten getätigt werden:&lt;br /&gt;
# eine Liste von devicetypen.&lt;br /&gt;
# Angabe einer devspec z.B. &amp;quot;TYPE=watchdog&amp;quot;. Hier ist zu beachten, dass in diesem Fall alle Geräte in die Ignoreliste einbezogen werden, die NICHT der devspec entsprechen. Weiterhin muss die devspec in Anführungszeichen gesetzt werden!&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Trigger_Filter ===&lt;br /&gt;
Beinhaltet eine Liste von Events, die bei eingehenden Events unberücksichtigt bleiben. Diese werde dann auch nicht gespeichert.&lt;br /&gt;
&lt;br /&gt;
Hier kann mit Wildcards (*) gearbeitet werden. Einzelne Events sind durch Komma &#039;,&#039; zu trennen.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (keine).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Wait (sec)===&lt;br /&gt;
Bei gesetztem Attribut (Zeit in Sekunden) nimmt Das MSwitch Device für den eingestellten Zeitraum keine Befehle mehr entgegen und ignoriert eingehende Events&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Event_Id_Distributor ===&lt;br /&gt;
Dieses Attribut hat nur dann eine Funktion, wenn auch das Attribut &#039;MSwitchExpert&#039; auf &#039;1&#039; gesetzt ist.&lt;br /&gt;
Hier können verschiedene auslösende Events auf Aktionen mit angegebenen IDs umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Sollte bei den &#039;trigger details :&#039; in einem Zweig ( cmd1 ) z.B. auf mehrere Events getriggert werden ( regex z.B. state:(on|off) ) so werden für beide Events jeweils der Zweig &#039;cmd1&#039; - alle  Aktionen ohneID - ausgeführt. Durch entsprechende Einträge kann für entsprechende Events auf eine Aktion umgeleitet werden, für die eine ID definiert ist. Die Syntax lautet:&lt;br /&gt;
:&amp;lt;code&amp;gt;state:on=&amp;gt;cmd1 ID 1,2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden bei auslösendem Event &#039;state:on&#039; nur die Aktionen aus cmd1 mit den IDs 1 und 2 ausgeführt. Mehrere Angaben sind durch new Line zu trennen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Selftrigger_always (0,1)===&lt;br /&gt;
(dieses Attribut steht ab Modulversion 2.5 zur Verfügung)&lt;br /&gt;
&lt;br /&gt;
Die Aktivierung dieses Attributes (1) bewirkt, dass alle SET Aktionen des Devices einen (internen) Event auslösen, auf die das Device selber reagiert. Diese Option kann zusätzlich zu einem vorhandenen Trigger aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Diese Events sind lediglich Device intern, d.h es werden keine Modulübergreifenden Events ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Auftretende und auswertbare interne Events haben immer folgendes Format und können darüber ausgewertet werden.&lt;br /&gt;
&lt;br /&gt;
MSwitch_Self:aktion:wert &lt;br /&gt;
MSwitch_Self:pct:100&lt;br /&gt;
&lt;br /&gt;
Es werden nur interne Events für set-Aktionen ausgelöst, die im Attribut setlist hinterlegt sind.&lt;br /&gt;
&lt;br /&gt;
Als weitere Besonderheit unterliegen diese internen Events nicht dem &#039;wait&#039; Befehl/Attribut.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Mode (Notify,Full,Toggle,Dummy)===&lt;br /&gt;
Schaltet das Modul zwischen verschiedenen Modi um, mit entsprechend angepasster Weboberfläche.&lt;br /&gt;
&lt;br /&gt;
==== Notify ====&lt;br /&gt;
Das Device kann nicht manuell umgeschaltet werden. Es gibt nur zwei ausführbare Zweige (execute &#039;cmd1&#039; commands und execute &#039;cmd2&#039; commands). Der Status des Devices wird nicht als &#039;on&#039; oder &#039;off&#039; angezeigt, sondern lediglich als &#039;active&#039;&lt;br /&gt;
&lt;br /&gt;
Dieser Mode ist am ehesten mit einem Notify zu Vergleichen.&lt;br /&gt;
&lt;br /&gt;
==== Full ====&lt;br /&gt;
Es stehen alle Funktionen zur Verfügung.&lt;br /&gt;
==== Toggle ====&lt;br /&gt;
Sehr vereinfachter Mode. Es stehen keine verschiedenen Zweige zur Verfügung. Hier ist das Device manuell schaltbar und wird bei jedem definierten Event &#039;Umgeschaltet&#039;, entsprechend definierte Befehle für &#039;cmd1&#039; oder &#039;cmd2&#039; werden ausgeführt.&lt;br /&gt;
==== Dummy====&lt;br /&gt;
ACHTUNG: Funktionsänderung mit V2.61&lt;br /&gt;
&lt;br /&gt;
Der Mode &#039;Dummy&#039; ist ein eingeschränkter Modus. &lt;br /&gt;
Dieser bietet die Funktionalität eines Dummys kombiniert mit der Funktionalität eines Notifys und kann somit die gerne genutzte Kombination Dummy-Notify gegen ein Device ersetzen.&lt;br /&gt;
&lt;br /&gt;
Achtung: Devices die einmal in dem Modus &#039;Dummy&#039; gesetzt wurden können nicht wieder in einen anderen Mode geschaltet werden ! &lt;br /&gt;
&lt;br /&gt;
Der Dummy-Mode kann nur in einem neu angelegtem, leeren MSwitch aktiviert werden. Sobald ein angelegtes MSwitch einmal verändert wurde (modify trigger etc.) ist ein Umschalten nicht mehr möglich und die Option nicht mehr verfügbar.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Condition_Time (0,1)===&lt;br /&gt;
In der Grundeinstellung (0) werden für das zeitgesteuerte Schalten keine definierten Conditionen im Feld &#039;Trigger condition&#039; überprüft, sondern die Schaltbefehle werden in jedem Fall ausgeführt. Mit der Einstellung (1) wird diese Überprüfung auch für zeitgesteuerte Befehle zugeschaltet.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Time (HH:MM:SS-HH:MM:SS)===&lt;br /&gt;
Bei Aktivierung wird vor jedem Ausführen eines verzögerten Befehls ( Delay ) eine Zufallszeit generiert, die im Rahme der hier angegebenen Zeitspanne liegt. Auf diese Zufallszahl kann in den Delays zugegriffen werden, durch die Angabe &#039;[random]&#039; statt einer direkten Zeitangabe. Bei nicht gesetztem Attribut ergibt die Angabe von &#039; [random] &#039; hier immer &#039;00:00:00&#039;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Number ===&lt;br /&gt;
Bei Aktivierung dieses Attributes (der Inhalt kann einen beliebige Zahl sein) werden vom Device 2 Readings angelegt (Device:RandomNr) und (Device:RandomNr1). RandomNr wird vor jedem Ausführen eines Befehls aktualisiert und neu generiert, d.h wenn ein MSwitch Device mehrere Geräte schaltet, wird (auch in einem Durchgang) vor jedem Befehl dieses Reading neu gesetzt. RandomNr1 wird lediglich bei Ausführung des MSwitch Devices einmal neu gesetzt, d.h. nicht vor jedem Befehl der ausgeführt wird.&lt;br /&gt;
Die Readings werden mit einer Zufallszahl zwischen 0 und dem hier eingestellten Wert gesetzt.&lt;br /&gt;
&lt;br /&gt;
Auf diese Readings kann in jeder Condition mit z.B. &#039;[$NAME:ReadingNr1] = 1&#039; zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
D.h., das in der Condition angegebene Reading ( [$NAME:ReadingNr1] ) muss in diesem Fall den Wert 1 angenommen haben, ansonsten wird der Befehl nicht ausgeführt. &lt;br /&gt;
Der Befehl wird somit nur mit einer Wahrscheinlichkeit von 1 zu ( gesetzter Wert im Attr. ) ausgeführt.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Reset_EVT_CMD1(2)_COUNT ===&lt;br /&gt;
Bei Aktivierung dieses Attributes steht in den Readings das Reading &#039;EVT_CMD1_COUNT&#039; bzw. &#039;EVT_CMD2_COUNT&#039; zur Verfügung. Dieses kann in den Conditions genutzt werden, um z.B. nur bei jedem x-ten Eintreffen eines auslösenden Events einen Befehl auszuführen. Bei jedem Eintreffen eines gültigen Events werden die Zähler um 1 erhöht (für den jeweiligen Zweig). &lt;br /&gt;
Ist hier der Wert &#039;0&#039; eingetragen, wird der Zähler fortlaufend (endlos) erhöht. Wird ein Wert größer 0 eingetragen, wird der Zähler mit Erreichen dieses Wertes automatisch wieder auf Null gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit Löschen dieses Attributes werden die entsprechenden Readings ebenfalls gelöscht.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Safemode (0:1)===&lt;br /&gt;
Bietet einen (gewissen) Schutz vor falschen Konfigurationen und somit entstehenden Endlosschleifen.&lt;br /&gt;
Bei aktiviertem Attribut (1) erkennt das Modul Endlosschleifen eines Devices und beendet diese.&lt;br /&gt;
&lt;br /&gt;
In diesem Fall erfolgt ein Logeintrag und das Device wird per Attribut auf &#039;Disabled&#039; gesetzt.&lt;br /&gt;
Es wird ein letztes Event generiert, auf das reagiert werden kann:&lt;br /&gt;
:&amp;lt;code&amp;gt;2018-05-31 09:39:21 MSwitch &amp;lt;NAME&amp;gt; Safemode: on&amp;lt;/code&amp;gt;&lt;br /&gt;
Im Webinterface erfolgt bei betroffenem Device ein entsprechender Hinweis.&lt;br /&gt;
&lt;br /&gt;
In der Grundkonfiguration ist dieses Attribut nicht gesetzt, es empfiehlt sich aber, bei neuen (komplizierten) Devices, dieses - zumindest anfänglich - zu aktivieren.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Read_Log(0:1)===&lt;br /&gt;
Ermöglicht den Zugriff auf das Logfile als Trigger.&lt;br /&gt;
&lt;br /&gt;
Hier gibt es mehrere Konfigurationsmöglichkeiten:&lt;br /&gt;
* Bei aktiviertem Attribut enthält die Auswahl des Triggerdevices die Option &#039;LOGFILE&#039;. Bei dieser Auswahl werde alle Logeinträge erkannt und in ein internes Event umgewandelt, auf das regiert werden kann.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl &#039;GLOBAL&#039; im &#039;Trigger_Device&#039; wird auf ALLE Events und alle Logeinträge reagiert.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl eines bestimmten Devices im &#039;Trigger_Device&#039; wird auf alle Events  und auf alle Logeinträge des gewählten Devices reagiert. Hier ist zu beachten, dass FHEM mir keine Möglichkeit bietet, wirklich herauszufinden, welches Device denn nun einen Logeintrag generiert hat. D.h., dieses wird vom Vorhandensein des Namens im Logeintrag abhängig gemacht und MSwitch reagiert nur dann auf einen Logeintrag, wenn der Name des Devices in diesem Eintrag vorhanden ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Help(0:1)===&lt;br /&gt;
Schaltet Hilfebuttons zu den einzelnen Eingabefeldern an oder aus.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Comments(0:1)===&lt;br /&gt;
Schaltet Kommentarfelder zu den einzelnen &#039;affected_devices an.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_generate_Events(0:1)===&lt;br /&gt;
Reduziert bei Einstellung &#039;1&#039; die vom MSwitch-Devices erzeugten Events auf ein absolutes Minimum. Insbesondere bei Verwendung von &#039;MSwitch_Read_Log&#039; zu empfehlen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay ===&lt;br /&gt;
Bestimmt die Verzögerungszeit des MSwitches nach FHEM-Start in Sekunden. In diesem Zeitraum reagiert das ??Event??(Red: ist hier &amp;quot;Device&amp;quot; gemeint?) nicht auf Events. Die Vorgabe ist hier zehn Sekunden. Diese wird auch dann angenommen, wenn das Attribut nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Inforoom ===&lt;br /&gt;
Mit diesem Attribut wird die Raumansicht eines mit dem Attribut bestimmten Raumes verändert. Dadurch sollen die wichtigsten Informationen aller MSwitch-Devices auf eine Seite dargestellt werden. Zur Nutzung sollten alle MSwitch-Devices (zusätzlich) in einen Raum sortiert werden und dieser Raum im Attribut eingestellt werden.&lt;br /&gt;
&lt;br /&gt;
Wichtig: Eine Änderung dieses Attributes bewirkt immer eine Änderung dieses Attributes in &#039;&#039;allen&#039;&#039; MSwitch devices: Es muss nur in einem Device gesetzt oder gelöscht werden um alle Devices zu erfassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
MSwitch_Screen_1.png|Raumansicht des Raumes MSwitch mit gesetztem Attribut &#039;MSwitch&#039;&lt;br /&gt;
MSwitch_Screen_2.png|Raumansicht des Raumes MSwitch ohne gesetztes Attribut&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es werden folgende Informationen bereitgestellt:&lt;br /&gt;
* Infobutton zeigt den im Device gespeicherten Textes des Attributes &#039;comment&#039;&lt;br /&gt;
* Device und Events, die das Device triggern&lt;br /&gt;
* Zeiten, zu denen verschiedene Zweige des Devices ausgeführt werden&lt;br /&gt;
* Devices, die durch das MSwitch Device geschaltet werden&lt;br /&gt;
* State des Devices&lt;br /&gt;
&lt;br /&gt;
== Integrierte Funktionen ==&lt;br /&gt;
&lt;br /&gt;
=== Average ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
=== Tendency ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[TEND&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;Mindestwert&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[TEND2:countdown] &amp;gt; 2&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Es wird jeweils der Durchschnitt von 2 Wertepaaren gebildet. In diesem Fall werden die letzten 4 Werte herangezogen.&amp;lt;br&amp;gt;&lt;br /&gt;
Paar 1 = Aktueller und letzter Wert, Paar 2 = Die 2 vorherigen Werte.&amp;lt;br&amp;gt;&lt;br /&gt;
Bei TEND3 werden die letzten 6 Werte zur Paarbildung genutzt.&lt;br /&gt;
&lt;br /&gt;
Mindestwert:&lt;br /&gt;
Der Wertunterschied zwischen den Wertepaaren, der minimal erreicht sein muss, um eine Tendenz zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Rechenzeichen (&amp;gt;&amp;lt;):&lt;br /&gt;
Dieses ist hier nicht als Rechenzeichen zu werten, sonder als Tendenz-Anzeige. ( &amp;lt; es wird nach fallender Tendenz gesucht / &amp;gt; sucht nach steigender Tendenz).&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolgt einmalig bei Erkennung der gesuchten Tendenz.&lt;br /&gt;
Danach erfolgt keine Schaltung mehr, solange bis eine Tendenz-Umkehr erfolgt ist.&lt;br /&gt;
Erst dann erfolgt wieder eine Schaltung bei erneuter Tendenz-Umkehr in gesuchte Richtung.&lt;br /&gt;
&lt;br /&gt;
=== Difference ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[DIFF&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;differenz&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[DIFF2:countdown] &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Gespeicherter Wert (in diesem Fall der vorletzte).&lt;br /&gt;
&lt;br /&gt;
Differenz:&lt;br /&gt;
Geforderter Differenz zwischen aktuellem und vorletztem Wert.&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolg wenn diese Bedingung &#039;wahr&#039; ist.&lt;br /&gt;
&lt;br /&gt;
Folgende Readings werden zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
DIFFERENCE (true/false) - Schaltbedingung erkannt ja/nein&lt;br /&gt;
&lt;br /&gt;
DIFFDIRECTION (up/down) - Richtung der erkannten Bedingung (steigend/fallend)&lt;br /&gt;
&lt;br /&gt;
=== Increase ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
== Tipps, Tricks, Kurzbeispiele ==&lt;br /&gt;
Wird stetig ergänzt .&lt;br /&gt;
&lt;br /&gt;
=== Blinken - Falls nicht im Device vorhanden ===&lt;br /&gt;
[[Datei:MSwitch MSwitchblink.png|center|704px]]&lt;br /&gt;
&amp;lt;br clear=all&amp;gt;&lt;br /&gt;
Lässt ein beliebiges Device 5 mal togglen, mit einem Intervall von 0.5 Sekunden (Blinkzeit somit 2,5 Sekunden)&amp;lt;br&amp;gt;&lt;br /&gt;
Die MSwitchtoggle-Funktion muss per ATTR aktiviert werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Die Repeatfunktion ist nur im Expertmode verfügbar, auch per ATTR einstellbar.&lt;br /&gt;
&lt;br /&gt;
=== Linearschalter ===&lt;br /&gt;
Umsetzung eines Linearschalters mit MSwitch.&lt;br /&gt;
&lt;br /&gt;
Eingang: Beliebiges Reading als numerischer Wert.&lt;br /&gt;
&lt;br /&gt;
Ausgang: Wird entsprechend Linear / oder umgekehrt Linear zum Eingang geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgend die Rawdefinition des MSwitchdevices und zweier Dummys (selbsterklärend)&lt;br /&gt;
&lt;br /&gt;
Alle Devices werden im Raum Lineartest angelegt, die Dummy müssen zuerst angelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod linearausgang dummy&lt;br /&gt;
attr linearausgang room Lineartest&lt;br /&gt;
attr linearausgang setList state:slider,0,1,100&lt;br /&gt;
attr linearausgang webCmd state&lt;br /&gt;
setstate linearausgang state 57&lt;br /&gt;
setstate linearausgang 2018-06-06 18:06:12 state state 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod lineareingang dummy&lt;br /&gt;
attr lineareingang room Lineartest&lt;br /&gt;
attr lineareingang setList state:slider,0,1,15000&lt;br /&gt;
attr lineareingang webCmd state&lt;br /&gt;
setstate lineareingang 6422&lt;br /&gt;
setstate lineareingang 2018-06-06 18:06:12 state 6422&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod Linearschalter MSwitch lineareingang  # linearausgang FreeCmd&lt;br /&gt;
attr Linearschalter MSwitch_Debug 0&lt;br /&gt;
attr Linearschalter MSwitch_Delete_Delays 1&lt;br /&gt;
attr Linearschalter MSwitch_Expert 0&lt;br /&gt;
attr Linearschalter MSwitch_Extensions 0&lt;br /&gt;
attr Linearschalter MSwitch_Help 0&lt;br /&gt;
attr Linearschalter MSwitch_Ignore_Types notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
attr Linearschalter MSwitch_Include_Devicecmds 1&lt;br /&gt;
attr Linearschalter MSwitch_Include_MSwitchcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Include_Webcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Inforoom MSwitch&lt;br /&gt;
attr Linearschalter MSwitch_Lock_Quickedit 1&lt;br /&gt;
attr Linearschalter MSwitch_Mode Notify&lt;br /&gt;
attr Linearschalter room Lineartest&lt;br /&gt;
&lt;br /&gt;
setstate Linearschalter active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:03:50 .Device_Affected FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:04:35 .Device_Affected_Details FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 );;my $emin=0;;my $emax=15000;;my $amin=100;;my $amax=0;;$eingang = $emin if $eingang &amp;lt; $emin;;$eingang = $emax if $eingang &amp;gt; $emax;;my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin;;readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 );;},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter:to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 .Device_Events no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .First_init done&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_on *&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_condition &lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_on no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_time &lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .V_Check V 0.3&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVENT state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTFULL lineareingang:state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART1 lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART2 state&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART3  6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 Exec_cmd set linearausgang state [Linearschalter:to_set]&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 Trigger_device lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 Trigger_log off&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 last_event state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:39:56 state active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 to_set 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
MSwitch -Configfile (bei Bedarf)&lt;br /&gt;
&amp;lt;pre&amp;gt;#V V1.54&lt;br /&gt;
#S .Device_Affected -&amp;gt; FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
#S .Device_Affected_Details -&amp;gt; FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 )[S]my $emin=0[S]my $emax=15000[S]my $amin=100[S]my $amax=0[S]$eingang = $emin if $eingang &amp;lt; $emin[S]$eingang = $emax if $eingang &amp;gt; $emax[S]my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin[S]readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 )[S]},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter.to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
#S .Device_Events -&amp;gt; no_trigger&lt;br /&gt;
#S .First_init -&amp;gt; done&lt;br /&gt;
#S .Trigger_Whitelist -&amp;gt; undef&lt;br /&gt;
#S .Trigger_cmd_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_cmd_on -&amp;gt; *&lt;br /&gt;
#S .Trigger_condition -&amp;gt; &lt;br /&gt;
#S .Trigger_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_on -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_time -&amp;gt; &lt;br /&gt;
#S .V_Check -&amp;gt; V 0.3&lt;br /&gt;
#S Trigger_device -&amp;gt; lineareingang&lt;br /&gt;
#S Trigger_log -&amp;gt; off&lt;br /&gt;
#S last_event -&amp;gt; state: 6422&lt;br /&gt;
#S state -&amp;gt; active&lt;br /&gt;
#A MSwitch_Ignore_Types -&amp;gt; notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
#A MSwitch_Include_MSwitchcmds -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Debug -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Help -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Devicecmds -&amp;gt; 1&lt;br /&gt;
#A MSwitch_Extensions -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Webcmds -&amp;gt; 0&lt;br /&gt;
#A room -&amp;gt; Lineartest&lt;br /&gt;
#A MSwitch_Inforoom -&amp;gt; MSwitch&lt;br /&gt;
#A MSwitch_Expert -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Lock_Quickedit -&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Thread über das Modul im {{Link2Forum|Topic=86199|LinkText=FHEM Forum}}&lt;br /&gt;
* {{Link2Forum|Topic=100119|Message=936495|LinkText=Gäste-WLAN der Fritzbox auswerten und Login per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=86199|Message=930133|LinkText=Schalten von vier Kanälen mit einem MSwitch-Device}}&lt;br /&gt;
* {{Link2Forum|Topic=99219|Message=926652|LinkText=Batterie-Überwachung. 1xTäglich per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=101091|Message=945389|LinkText=Licht (Alarm) in einem bestimmten Zeitraum schalten}}&lt;br /&gt;
* {{Link2Forum|Topic=100949|Message=944284|LinkText=Über Dummy-Schalter ein Timer (EIN/AUS) aktivieren}}&lt;br /&gt;
* {{Link2Forum|Topic=103083|Message=967710|LinkText=Ladezeit von Akku ermitteln u. Steckdose entsprechend schalten}}&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31478</id>
		<title>MSwitch</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31478"/>
		<updated>2019-11-01T20:00:52Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* Notify */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[MSwitch]] ist ein Hilfsmodul, welches das Event- und/oder zeitgesteuerte Schalten von mehreren Devices oder das Ausführen von benutzerdefinierten Befehlssequenzen erlaubt.&lt;br /&gt;
&lt;br /&gt;
Die Stärke bzw. das Unterscheidungsmerkmal dieses Moduls liegt in der Konfigurierbarkeit über ein Webinterface. Diese Konfiguration kann jederzeit geändert oder erweitert werden. &lt;br /&gt;
&lt;br /&gt;
Byte09: &#039;&#039;Die Grundidee zu MSwitch kam mir, weil ich bei der Arbeit mit FHEM für meinen Geschmack zu viele Module für die verschiedenen Aufgaben brauchte - zu allem Überfluss alle mit unterschiedlicher Syntax. Zwar ist DOIF hiervon ausgenommen (da hiermit wohl auch fast jede Aufgabe lösbar ist), aber ich konnte mich leider nicht daran gewöhnen und somit wurde jedes DOIF für mich zu einem echten Projekt. Was ich wollte war ein Modul, mit dem ich alles erledigen kann. Daher entschloss ich mich schon nach fast einem knappen Jahr FHEM-Nutzung mein eigenes Modul zu schreiben, welches diese Anforderung erfüllt. MSwitch beinhaltet die Funktionalität aller bisherigen Hilfsmodule wie z.B. Notify, Doif, Watchdog, Dummy,( ab Modulversion 2.2 auch Sequenz ) es lassen sich all deren Funktionen umsetzen.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;MSwitch wird permanent - vorrangig nach meinen Bedürfnissen - weiterentwickelt, gerne nehme ich aber auch Anregungen von anderen Nutzern auf.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=MSwitch&lt;br /&gt;
|ModType=h&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=98_MSwitch.pm&lt;br /&gt;
|ModOwner=Byte09}}&lt;br /&gt;
&lt;br /&gt;
== Grundsätzliche Überlegungen ==&lt;br /&gt;
Um das Modul zu nutzen, muss man zuerst folgende Fragen beantworten:&lt;br /&gt;
&lt;br /&gt;
* Welches Gerät soll auslösen oder zu welcher Zeit soll eine Auslösung erfolgen.&lt;br /&gt;
: Dies ist der Trigger. Jedes Event aus dem Eventmonitor kann als Trigger dienen. Will man mehrere Geräte als gleichzeitige Auslöser betreiben, so muss das Device GLOBAL gewählt und die entsprechenden Geräte angegeben werden (dies erzeugt höhere Systemlast und ist nur im Expert-Modus verfügbar). Weiterhin kann auch zu fest definierten Zeiten, Zufallszeiten oder Intervallen, unabhängig von einem Trigger, geschaltet werden; auch eine Kombination beider Varianten ist möglich. Diese Einstellungen erfolgen im ersten Teil des Webinterfaces.&lt;br /&gt;
&lt;br /&gt;
* Welche Bedingungen sollen bei Auslösung erfüllt sein?&lt;br /&gt;
: Wenn diese Bedingungen erfüllt sind, werden Kommandos ausgelöst. Die Bedingungen werden im zweiten Teil des Webinterfaces eingegeben. Dabei unterscheidet das Modul zwischen zwei Kommando-Kanälen (cmd1 und cmd2) und den dazugehörigen Geräten.&lt;br /&gt;
&lt;br /&gt;
* Welche Kommandos sollen ausgelöst werden?&lt;br /&gt;
: Im dritten Teil des Webinterfaces werden dann die konkreten Kommandos eingegeben. Typischerweise wählt man dabei aus einer Liste der Kommandos aus, die die zugehörigen Geräte insgesamt aufweisen (also so, wie man auf den Geräteseiten selber Kommandos auswählt). Es gibt zudem ein so genanntes FreeCmd, das ein Geräteunabhängiges Kommando zulässt, beispielsweise reinen Perl-Code.&lt;br /&gt;
&lt;br /&gt;
* Welche weiteren Bedingungen sollen noch gelten?&lt;br /&gt;
: Hier sind Ereignisgesteuerte wie auch Zeitgesteuerte Bedingungen möglich. Diese Bedingungen werden auch in dem dritten Teil des Webinterfaces eingetragen. So sind Verzögerungen und Wiederholungen und weitere Bedingungen möglich.&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen, Installation und Grundbefehle ==&lt;br /&gt;
Das MSwitch-Modul ist ohne weitere Voraussetzungen nutzbar und wird derzeit in der Version 2.08 über FHEM Update verteilt. &lt;br /&gt;
&lt;br /&gt;
=== Definition und Einrichtung ===&lt;br /&gt;
Mit Hilfe von MSwitch kann man mehrere Devices gleichzeitig schalten. Diese Schaltungen befinden sich in zwei möglichen Zweigen bei MSwitch. Dabei unterscheidet man im Modul zwischen den beiden Kommandos cmd1 und cmd2. Die zu einem Kommando gehörenden Geräte werden wir auch Zweig nennen. Die einzelnen Devices jedes Zweiges können mit weiteren Schaltbedingungen versehen werden (zeit- oder ereignisgesteuert). &lt;br /&gt;
&lt;br /&gt;
Folgende Möglichkeiten zum definieren des MSwitch Devices stehen zur Verfügung:&lt;br /&gt;
:&amp;lt;code&amp;gt;define &amp;lt;name&amp;gt; MSwitch&amp;lt;/code&amp;gt;&lt;br /&gt;
Es wird ein leeres Device angelegt, das dann komplett über das Webinterface konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das define eines MSwitch Devices generiert lediglich eine &#039;leere Hülle&#039;. Alle relevante Einstellungen werden in Readings und/oder Hashes gespeichert. Daher stehen relevanten Daten &#039;&#039;nicht&#039;&#039; in der fhem.cfg! Vielmehr finden sich diese Daten in der Datei fhem.save (die Speicherung erfolgt durch den Befehl Fhemsave).&lt;br /&gt;
&lt;br /&gt;
=== set-Befehle ===&lt;br /&gt;
Es sind derzeit die folgenden set-Befehle implementiert.&lt;br /&gt;
&lt;br /&gt;
==== set active ====&lt;br /&gt;
Setzt das Device in den Status &#039;active&#039;.&lt;br /&gt;
&lt;br /&gt;
==== set inactive ====&lt;br /&gt;
Setzt das Device in den Status &#039;inactive&#039;, es werden keine Befehle mehr ausgeführt. Dieser Status entspricht dem Attribut &#039;disable&#039;, ist aber nicht mit dem roten Fragezeichen (fhem save) verbunden.&lt;br /&gt;
&lt;br /&gt;
==== set on/off [&amp;lt;parameter&amp;gt;]====&lt;br /&gt;
Setzt das Device in den Status &#039;on&#039; oder &#039;off&#039;. Alle Befehle der &#039;on/off-Zweige&#039; werden ausgeführt.&lt;br /&gt;
Optional kann den Befehlen &#039;on&#039; und &#039;off&#039; ein weiterer Parameter mit übergeben werden. Dieser wird im Reading &#039;Parameter&#039; hinterlegt und es kann sofort in &#039;Freecmds&#039; oder &#039;Conditions&#039; darauf zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
==== set reload_timer ====&lt;br /&gt;
Alle gesetzten Timer werden gelöscht und neu berechnet.&lt;br /&gt;
&lt;br /&gt;
==== set change_renamed &amp;lt;oldname&amp;gt; &amp;lt;newname&amp;gt; ====&lt;br /&gt;
Sollten sich Devicenammen im ausführenden Teil geändert habe (affected Devices, Conditions, etc.) so kann das MSwitch mit diesem Befehl angepasst werden, ohne alle Einstellungen neu einstellen zu müssen.&lt;br /&gt;
&lt;br /&gt;
==== set exec_cmd1 / set exec_cmd1 ID [&amp;lt;ID&amp;gt;] ====&lt;br /&gt;
Bewirkt das sofortige Ausführen des entsprechenden Befehlszweiges. Bei Angabe einer ID werden nur die Befehle mit der entsprechenden ID ausgeführt.&lt;br /&gt;
&lt;br /&gt;
==== set MSwitch_backup ====&lt;br /&gt;
Erstellt eine Backup-Datei aller MSwitch Devices unter ./fhem/MSwitch_backup.cfg.&lt;br /&gt;
&lt;br /&gt;
Daten dieser Datei können im Bedarfsfall für einzelne oder gleichzeitig alle MSwitch Devices wieder zurückgespielt (hergestellt) werden.&lt;br /&gt;
&lt;br /&gt;
==== set del_delays ====&lt;br /&gt;
Löscht alle anstehenden, verzögerten Befehle (delays).&lt;br /&gt;
&lt;br /&gt;
==== set reset_cmd_count:1,2 ====&lt;br /&gt;
Löscht das entsprechende EVT_CMD_COUNT - Reading (entspricht Rückstellung auf &#039;0&#039;).&lt;br /&gt;
&lt;br /&gt;
==== set fakeevent [&amp;lt;device&amp;gt;]:&amp;lt;reading&amp;gt;:&amp;lt;arg&amp;gt; ====&lt;br /&gt;
Beispiel: &amp;lt;device&amp;gt; fakeevent state:on&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ob der Name (&amp;lt;device&amp;gt;) angegeben werden muss, oder nicht, ist abhängig davon, ob auf ein einzelnes Device, oder GLOBAL getriggert wird. Bei GLOBALEN Triggern muss das Device mit angegeben werden. Wird auf ein Device getriggert, so wird das Device automatisch gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit diesem Befehl kann das MSwitch Device neu getriggert werden, indem hier ein Event &#039;gefaked&#039; wird. Das MSwitch Device reagiert dann so, als wäre dieses Event vom getriggerten Gerät generiert worden. &lt;br /&gt;
&lt;br /&gt;
Dieses kann nötig sein, um z.B. einen Watchdog zu realisieren, in dem es nötig ist, dass sich das MSwitch Device mit einem bestimmten Event selber neu triggert - ggf. mit einem entsprechenden Delay (affected Device muss dafür u.A. des MSwitch Device selber sein).&lt;br /&gt;
&lt;br /&gt;
Es wird hierbei KEIN echtes Event generiert welches das System beeinflusst, sondern ausschließlich ein MSwitch-Interner Befehl umgesetzt!&lt;br /&gt;
&lt;br /&gt;
Bei dem Einsatz dieser Möglichkeit sollte das Attribut &#039;MSwitch_Safemode&#039; UNBEDINGT aktiviert sein, da &#039;Experimente&#039; hier schnell in einer Endlosschleife enden können, die nur durch ein Reboot unterbrochen werden kann. &lt;br /&gt;
&lt;br /&gt;
Ggf. werde ich hier sogar eine entsprechende Änderung vornehmen, dass dieser Befehl nur zur Verfügung steht, wenn Safemode aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
=== get-Befehle ===&lt;br /&gt;
==== get show_timer [&amp;lt;show&amp;gt;&amp;lt;delete&amp;gt;] ====&lt;br /&gt;
;Show&lt;br /&gt;
:Zeigt alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren.&lt;br /&gt;
;Delete&lt;br /&gt;
:Löscht alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren. Schaltbefehle basierend auf rein zeitabhängigen Angaben werden neu berechnet und gesetzt.&lt;br /&gt;
&lt;br /&gt;
==== get restore_MSwitch_data [&amp;lt;this_device&amp;gt;&amp;lt;all_devices&amp;gt;] ====&lt;br /&gt;
;this_device&lt;br /&gt;
:Stellt die Daten des Devices aus der Backupdatei wieder her, sofern diese in der Backupdatei gefunden werden (gesucht wird hier nach dem Namen des Devices).&lt;br /&gt;
;all_devices&lt;br /&gt;
:Stellt die Daten aller MSwitch Devices wieder her, sofern diese in der Backupdatei vorhanden sind. Diese Aktion kann einige Zeit in Anspruch nehmen und wird daher im Hintergrund (nonblocking) ausgeführt. Nach Beendigung erfolgt eine Benachrichtigung.&lt;br /&gt;
&lt;br /&gt;
Die Devices sind nach einem Restore funktionsfähig. Empfohlen wird ein Neustart von FHEM.&lt;br /&gt;
&lt;br /&gt;
==== get_config ==== &lt;br /&gt;
Zeigt die Konfigurationsdatei des MSwitchdevices an; diese kann in dem Fenster editiert werden. Das sollte nur von erfahrenen Usern getan werden! Im Normalfall sollte das Device nur über die Weboberfläche konfiguriert werden und eine falsche Konfiguration kann hier zu einem FHEM Absturz führen.&lt;br /&gt;
&lt;br /&gt;
==== get_support_info ==== &lt;br /&gt;
Öffnet ein Fenster mit einer formatierten Ansicht aller Einstellungen des Devices. Bei Supportanfragen sollte dieses immer mit geposted werden.&lt;br /&gt;
&lt;br /&gt;
==== get_MSwitch_preconf ====&lt;br /&gt;
Lädt vorkonfigurierte MSwitch-Devices. Diese Option ist nur dann vorhanden, wenn das Aktualisieren dieser vorkonfigurierten Devices im FHEM Update aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
Diese kann durch ein einmaliges Update erfolgen mit:&lt;br /&gt;
:&amp;lt;code&amp;gt;update all https://raw.githubusercontent.com/Byte009/MSwitch_Addons/master/controls_mswitchaddons.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Webinterface ==&lt;br /&gt;
MSwitch wird im Wesentlichen über das Webinterface eingerichtet. Wählt man das folgende Attribut&lt;br /&gt;
:&amp;lt;code&amp;gt;attr &amp;lt;name&amp;gt; MSwitch_Help 1&amp;lt;/code&amp;gt;&lt;br /&gt;
so wird im Modul selber eine sehr umfangreiche Hilfe angezeigt. Über das gesamte Webinterface hinweg erscheinen kleine Fragezeichen, die man anklicken kann und die beschreiben, was in dem jeweiligen Textfeld sinnvollerweise einzugeben ist bzw. was das Modul an dieser Stelle erwartet.&lt;br /&gt;
&lt;br /&gt;
Das Webinterface besteht aus vier Teilen. Änderungen in jedem Abschnitt müssen in dem jeweiligen Teil bestätigt werden und auch nur diese werden gespeichert. Bevor ein weiterer Teil bearbeitet wird, sollten Änderungen gespeichert werden, sie gehen sonst verloren.&lt;br /&gt;
&lt;br /&gt;
=== Trigger device/time ===&lt;br /&gt;
==== Trigger Device ====&lt;br /&gt;
In diesem Feld wird das Device ausgewählt, dessen Events eine Aktion auslösen sollen. Dazu werden alle verfügbaren Devices in einem Dropdownfeld angeboten.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es eine Auswahl &#039;GLOBAL&#039;, wenn das Attribut &#039;MSwitch_Expert&#039; gesetzt ist. Bei Auswahl dieser Option werden &#039;&#039;&#039;alle&#039;&#039;&#039; von FHEM generierten Events durch das MSwitch Device weiterverarbeitet, eine weitere Begrenzung der aktivierenden Events kann (und sollte) dann in einem folgenden Eingabefeld erfolgen, um die Systemlast zu reduzieren.&lt;br /&gt;
&lt;br /&gt;
==== Trigger Device Global Whitelist ====&lt;br /&gt;
Dieses Feld ist nur verfügbar, wenn als Trigger &#039;GLOBAL&#039; gewählt wurde.&lt;br /&gt;
&lt;br /&gt;
Hier kann die Liste eingehender Events weiter eingeschränkt werden. Es handelt sich um eine Whitelist, d.h., wenn es keine Einträge gibt, werden Events aller Devices verarbeitet. Sobald ein oder mehrere Einträge gemacht werden, werden nur noch Events der hier benannten Devices verarbeitet. Als Angabe können hier Devices benannt werden oder ganze DeviceTypen (z.B. TYPE=FS20). Mehrere Angaben sind durch Komma zu trennen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:MSwitchWebinterface1.png|400px|thumb|right|Webinterface, oben]]&lt;br /&gt;
Im gezeigten Beispiel wurde GLOBAL gewählt, weil nicht ein einzelnes Device, sondern eine Kombination aus zwei Geräten auslösen soll. Es werden also alle Ereignisse betrachtet, wobei die Whitelist dann auf die Devices Schlafzimmer (ein Temperaturmessgerät) und Schlafzimmerfenster (ein [[HM-Sec-SCo Tür-Fensterkontakt, optisch|optischer Kontakt]]) einschränkt. &lt;br /&gt;
&lt;br /&gt;
==== Trigger time ==== &lt;br /&gt;
Es besteht die Möglichkeit, das Modul (neben den Events) zu festen Zeiten auszulösen. Dann wären in die leer stehenden Zeilen bei &amp;quot;at&amp;quot; entsprechende Termine einzutragen. Zeitangaben erfolgen durch [STUNDEN:MINUTEN|TAGE], wobei die Tage von 1-7 gezählt werden (1 steht für Montag, 7 für Sonntag usw.). &lt;br /&gt;
Mehrere Zeitvorgaben können direkt aneinandergereiht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [17:00|1][18:30|23] den Trigger montags um 17 Uhr auslösen und dienstags sowie mittwochs um 18:30 Uhr.&lt;br /&gt;
Bei [00:10*20:00-21:00] würde der Schaltbefehl von 21 Uhr bis 21 Uhr alle 10 Minuten ausgeführt. Bei [?20:00-21:00] würde der Schaltbefehl zu einem zufälligen Zeitpunkt zwischen 20 und 21 Uhr ausgeführt.  [20:00|$we] bedeutet, dass nur am Wochenende um 20:00 geschaltet wird.&lt;br /&gt;
&lt;br /&gt;
==== Trigger conditions ====&lt;br /&gt;
Hier kann die Angabe von Bedingungen erfolgen, die zusätzlich zu dem triggernden Device erfüllt sein müssen.&lt;br /&gt;
Diese Bedingungen sind eng an DOIF-Syntax angelehnt. Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich.&lt;br /&gt;
&lt;br /&gt;
Wird in diesem Feld keine Angabe gemacht, so erfolgt der Schaltvorgang nur durch das triggernde Device ohne weitere Bedingungen.&lt;br /&gt;
&lt;br /&gt;
;Zeitabhängigkeit&lt;br /&gt;
:[19:10-23:00] - Trigger des Devices erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
;Readingabhängige Trigger&lt;br /&gt;
:[Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Trigger des Device erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
:Werden Readings mit Strings abgefragt (on,off,etc.), ist statt des Gleichheitszeichens &amp;quot;=&amp;quot; der Operator &amp;quot;eq&amp;quot; zu nutzen, der String muss in Anführungszeichen &amp;quot;&amp;quot; gesetzt werden.&lt;br /&gt;
;mehrere Beispiele&lt;br /&gt;
:[19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
:[19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
:[10:00-11:00|13] - schaltet Montag und Mittwoch zwischen 10 Uhr und 11 Uhr.&lt;br /&gt;
:[{ sunset() }-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
:{ !$we } löst den Schaltvorgang nur Werktagen an aus.&lt;br /&gt;
:{ $we } löst den Schaltvorgang nur an Wochenenden, Feiertagen aus.&lt;br /&gt;
&lt;br /&gt;
Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (beispielsweise würde dann am Mittwoch noch der Schaltvorgang erfolgen, obwohl als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
Bedingungen in diesem Feld gelten nur für auslösende Trigger eines Devices und haben keinen Einfluss auf zeitgesteuerte Auslöser.&lt;br /&gt;
&lt;br /&gt;
=== Trigger details ===&lt;br /&gt;
[[Datei:MSwitchWebinterface2.png|600px|thumb|right|Webinterface, Mitte]]&lt;br /&gt;
Während im obigen Feld das Device ausgewählt  werden konnte, wird hier das Ereignis festgelegt. Das Eingabefeld besteht aus mehreren Einzelfeldern.&lt;br /&gt;
&lt;br /&gt;
Im abgebildeten Fall wird cmd1 ausgelöst, wenn der Zustand des Schlafzimmerfenster-Sensors meldet, dass das Fenster offen ist. Cmd2 wird ausgelöst, wenn die Temperatur des Schlafzimmersensors unter einen bestimmten Wert fallen wird.&lt;br /&gt;
&lt;br /&gt;
==== execute &#039;cmd1/cmd2&#039;  ====&lt;br /&gt;
Hier kann  aus einer vorbelegten Dropdownliste ausgewählt werden, welches ankommende Event den entsprechenden Befehlszweig auslösen soll. In dieser Liste werden bei entsprechender Einstellung alle ankommenden Events eines vorher definierten Devices gespeichert. In einem weiteren Feld (siehe unten) können Events manuell zugefügt werden.&lt;br /&gt;
&lt;br /&gt;
==== Save incomming events ====&lt;br /&gt;
Bei Aktivierung dieser Option werden alle ankommenden Events des oben definierten Devices (oder Global) gespeichert und in entsprechenden Dropdownlisten angeboten.&lt;br /&gt;
&lt;br /&gt;
Da hier doch erhebliche Datenmengen anfallen können (je nach Device) wird empfohlen, diese Option nach der Konfiguration des Devices zu deaktivieren.&lt;br /&gt;
&lt;br /&gt;
==== add event ====&lt;br /&gt;
Hier besteht die Möglichkeit, unabhängig von der Option, ankommende Events automatisch zu speichern. Manuell Events anzulegen, die in den Dropdownliste zur Auswahl angeboten werden, ohne das entsprechendes Event erst vom Device geliefert werden muss.&lt;br /&gt;
&lt;br /&gt;
Es können mehrere Events gleichzeitig eingegeben werden, eine Trennung erfolgt durch &amp;quot; , &amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Hier ist zu unterscheiden, ob das gewählte triggernde Device ein einfaches Device ist oder ob der Trigger &#039;GLOBAL&#039; ist.&lt;br /&gt;
Bei triggernden Devices können Events in folgendem Formaten zugefügt werden:&lt;br /&gt;
&lt;br /&gt;
- *                                                    - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:wert   (z.b. state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:*      (z.b. state:* )                       - Aktion erfolgt auf die Events &amp;quot;state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:(wert1/wert2/wert3) (z.b. state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;state:left&amp;quot; oder &amp;quot;state:right&amp;quot; etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Falls auf &#039;GLOBALE&#039; Events getriggert wird, muss das auslösende Device vorangestellt werden:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
- *                                                           - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:wert   (z.b. device:state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;device:state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:*      (z.b. device:state:* )                       - Aktion erfolgt auf die Events &amp;quot;device:state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:(wert1/wert2/wert3) (z.b. device:state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;device:state:left&amp;quot; oder &amp;quot;devicestate:right&amp;quot; etc.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Device kann auch hier gegen &amp;quot;*&amp;quot; ersetzt werden (*:state:on). In diesem Fall erfolgt eine Aktion auf alle Events die z.B. &amp;quot;state:on&amp;quot; enthalten, egal welches Device triggert.&lt;br /&gt;
&lt;br /&gt;
==== test event ====&lt;br /&gt;
Dieses Feld wird angeboten, wenn entsprechende vom Triggerdevice gelieferte Events gespeichert wurden.&lt;br /&gt;
&lt;br /&gt;
Durch Auslösen dieser Funktion wird das Event simuliert und entsprechende definierte Aktionen ausgelöst. Diese Funktion dient ausschließlich zum Testen der eingestellten Konfiguration. Alle entsprechenden Befehle werden ausgeführt, als würde das Event real eintreffen.&lt;br /&gt;
&lt;br /&gt;
==== apply filter to saved events ====&lt;br /&gt;
Beschreibung folgt&lt;br /&gt;
&lt;br /&gt;
==== clear saved event ====&lt;br /&gt;
Es werden alle gespeicherten Events gelöscht.&lt;br /&gt;
&lt;br /&gt;
Ausnahme: Events, die als Trigger eingestellt sind, bleiben erhalten.&lt;br /&gt;
&lt;br /&gt;
=== Affected devices ===&lt;br /&gt;
[[Datei:MSwitch_Screen_5.png|mini|rechts|affected devices]]&lt;br /&gt;
Dieser Abschnitt beinhaltet die Auswahl der Devices, die auf ein Event reagieren sollen.&lt;br /&gt;
&lt;br /&gt;
In dem Auswahlfeld werden alle Devices angeboten, die eines der folgenden Kriterien erfüllen:&lt;br /&gt;
# Die Abfrage &amp;quot;set Device ?&amp;quot; liefert einen Befehlssatz&lt;br /&gt;
# Das Attribut &#039;webcmd&#039; des Devices enthält Einträge&lt;br /&gt;
# Das Attribut &#039;MSwitch_Activate_MSwitchcmds&#039; ist aktiviert und das Attribut &#039;MSwitchcmds&#039; des betreffenden Devices enthält einen Befehlssatz&lt;br /&gt;
&lt;br /&gt;
Einzige Ausnahme ist der erste Listeneintrag &#039;FreeCMD&#039;. Die Auswahl dieses Eintrages bietet später die Möglichkeit Befehle auszuführen, die nicht an ein Device gebunden sind. Der Code in einem FreeCmd kann entweder reiner FHEM-Code sein ( set device on ) oder reiner Perl-Code. Wenn es sich um reinen Perl-Code handelt, ist dieser in geschweifte Klammen zu setzen { Perl-Code }.&lt;br /&gt;
&lt;br /&gt;
=== Device actions ===&lt;br /&gt;
[[Datei:Webinterface3.png|mini|rechts|device_actions]]&lt;br /&gt;
Hier stellt man die auszuführenden Aktionen der eingestellten Devices ein. Im ersten Abschnitt oben befindet sich ein FreeCmd, mit dem beliebige Kommandos eingetragen werden können. Im abgebildeten Beispiel ist dies sogar selbst definierter Perl-Code (die Funktion DebianMail sendet eine Mail). &lt;br /&gt;
&lt;br /&gt;
==== MSwitch cmd1/cmd2:  ====&lt;br /&gt;
Man wählt den Befehl aus dem betreffenden Device aus. Bei freien Textfeldern (wie im Fall des FreeCmd) wird der Befehl eingegeben.&lt;br /&gt;
&lt;br /&gt;
Es werden alle verfügbaren Befehle des Devices zur Auswahl angeboten. Je nach Attribut-Einstellungen werden Einträge aus entsprechenden &#039;webcmds&amp;quot; oder &#039;MSwitchcmds&#039; einbezogen. In Abhängigkeit des Befehls stehen unter Umständen weitere Felder oder Widgets zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
05.04.2018 NEU: Auswahlfeld &#039;MSwitchtoggle&#039; -&amp;gt; Beschreibung wird noch ergänzt !&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 condition  ====&lt;br /&gt;
Mit diesem Feld kann die Ausführung des Befehls von weiteren Bedingungen abhängig gemacht werden. Bei der Abfrage von Readings nach Strings (on, off, etc.) ist statt &amp;quot;=&amp;quot; &amp;quot;eq&amp;quot; zu nutzen und der String muss in &amp;quot;x&amp;quot; gesetzt werden. Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
#Zeitabhängiges schalten: [19:10-23:00] - Schaltbefehl erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
#Readingabhängiges schalten [Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Schaltbefehl erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
&lt;br /&gt;
Soll nur an bestimmten Wochentagen geschaltet werden, muss eine Zeitangabe gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [10:00-11:00|13] den Schaltvorgang nur Montag und Mittwoch zwischen 10 Uhr und 11 Uhr auslösen. Hierbei zählen die Wochentage von 1-7 für Montag-Sonntag.&lt;br /&gt;
&lt;br /&gt;
Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich:&lt;br /&gt;
* [19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
* [19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
* [{sunset()}-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
* { !$we } löst den Schaltvorgang nur Werktagen aus&lt;br /&gt;
* { $we } löst den Schaltvorgang nur Wochenenden, Feiertagen aus&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung:&#039;&#039;&#039; Bei Anwendung der geschweiften Klammern zur Einleitung eines Perl Ausdrucks ist unbedingt auf die Leerzeichen hinter und vor der Klammer zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (zum Beispiel würde auch am Mittwoch noch der Schaltvorgang erfolgen, wenn als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
; $EVENT:&lt;br /&gt;
: Die Variable EVENT enthält den auslösenden Trigger, d.h. es kann eine Reaktion in direkter Abhängigkeit zum auslösenden Trigger erfolgen.&lt;br /&gt;
&lt;br /&gt;
[$EVENT] eq &amp;quot;state:on&amp;quot; würde den Kommandozweig nur dann ausführen, wenn der auslösende Trigger &amp;quot;state:on&amp;quot; war. Wichtig ist dieses, wenn bei den Triggerdetails nicht schon auf ein bestimmtes Event getriggert wird, sondern hier durch die Nutzung eines Wildcards (*) auf alle Events getriggert wird, oder auf alle Events eines Readings z.B. (state:*).&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 delay  ====&lt;br /&gt;
Ein Eintrag in diesem Feld führt zur verzögerten Ausführung des Befehls nach Eintreffen des Events. Dabei kann der Befehl ohne weitere Prüfung der Bedingung ausgelöst werden. Es ist aber auch möglich, dass die Bedingung bei Ausführung erneut geprüft wird. Die Zeitangabe muss im Format hh:mm:ss vorliegen.&lt;br /&gt;
&lt;br /&gt;
Statt einer unmittelbaren Zeitangabe kann hier auch ein Verweis auf ein Reading eines Devices erfolgen :&amp;lt;br&amp;gt;&lt;br /&gt;
[NAME.reading] des Devices -&amp;gt;z.B. [dummy.state]&lt;br /&gt;
&lt;br /&gt;
==== add action  ====&lt;br /&gt;
Mit diesem Button kann ein weiteres Eingabefeld für das entsprechende Device angelegt werden, um z.B. einen weiteren Befehl (ggf.) zeitverzögert auszuführen.&lt;br /&gt;
&lt;br /&gt;
==== delete this action  ====&lt;br /&gt;
Mit diesem Button wird der entsprechende Befehl für das Device gelöscht.&lt;br /&gt;
&lt;br /&gt;
==== check condition  ====&lt;br /&gt;
[[Datei:MSwitch_Screen_7.png|mini|rechts|check]]&lt;br /&gt;
Die angegebenen &#039;conditions&#039; werden in Zusammenhang mit ggf. ausgewählten Devices auf Syntax und Ergebnis geprüft. Es erfolgt eine Ausgabe des Prüfungsergebnisses.&lt;br /&gt;
&lt;br /&gt;
==== Repeat und Repeatdelay ====&lt;br /&gt;
Man kann mehrfache Wiederholungen erzwingen. Repeat gibt dabei an, wie oft das Kommando wiederholt wird (Anzahl). Repeatdelay gibt an, wie viel Sekunden zwischen einzelnen Wiederholungen liegen sollen.&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Folgende Attribute stehen zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Debug (0:1:2:3:4) ===&lt;br /&gt;
0 - Abgeschaltet&amp;lt;br&amp;gt;&lt;br /&gt;
1 - Schaltet Felder zum testen der Conditionstrings etc. an&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Alle ausgehenden Befehle werden nur simuliert und nicht ausgeführt. Es erfolgt eine Protokollierung in einer separaten Datei . Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Es erfolgt eine Protokollierung in einer separaten Datei . Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
4 - erweiterte Debugfunktion (nur für Entwicklung - wechselnde Funktion )&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Expert (0:1) ===&lt;br /&gt;
In der Liste der möglichen Trigger erscheint das Selectfeld &#039;GLOBAL&#039;. Dieses ermöglicht das Setzen eines Triggers auf alle Events und damit nicht nur auf einzelne Devices. In einem weiteren Feld kann eine weitere Selektion der triggernden Events erfolgen.&lt;br /&gt;
&lt;br /&gt;
Es stehen weitere Felder &#039;Repeats&#039; und &#039;Repeatdelay in sec&#039; zur Verfügung. Eine hier getätigte Einstellung bewirkt X-fache Wiederholung von gesetzten Befehlen im Abstand der gesetzten Sekunden.&lt;br /&gt;
&lt;br /&gt;
Weiterhin kann über das Auswahlfeld &#039;priotity&#039; bei jedem &#039;affectes device&#039; die Reihenfolge beim abarbeiten der Befehle beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequenz &amp;lt;Suchmuster&amp;gt; ===&lt;br /&gt;
In diesem Attribut können ein oder mehrere Suchmuster angegeben werden ,die eine Schaltsequenz darstellen und vom Device erkannt werden.&lt;br /&gt;
&lt;br /&gt;
Die Angabe muss folgende Syntax haben:&lt;br /&gt;
:&amp;lt;code&amp;gt;Device1:reading1:event1 Device1:reading1:event1-2 Device1:reading1:event1-3/..../....&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mehrere Suchmuster müssen durch &amp;quot;/&amp;quot; getrennt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
:&amp;lt;code&amp;gt;Dummy:state:on Dummy:state:off Dummy:state:on&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erkennt das Device dieses Suchmuster in den Schaltvorgängen des Devices (Dummy), wird das Reading &amp;quot;SEQUENCE&amp;quot; auf &amp;quot;match&amp;quot; gesetzt, das Reading &amp;quot;SEQUENCE_NUMBER&amp;quot; auf die Nummer der gefundenen Sequenz, wenn es mehrere Suchmuster gibt. Beide Readings können in den &amp;quot;Conditions&amp;quot; eines Schaltbefehles abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequence_time &amp;lt;Zeit in Sekunden&amp;gt; ===&lt;br /&gt;
Beinhaltet die Zeit in Sekunden, die es dauern darf, um eine Sequenz vollständig auszuführen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Extensions (0:1) ===&lt;br /&gt;
Es wird eine zusätzliche Schaltoption &#039;MSwitchToggle&#039; in den Geräten angeboten. Diese kann genutzt werden, wenn zuschaltende Geräte eine Togglefunktion nicht von Haus aus anbieten.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe muss in folgendem Format gemacht werden:&lt;br /&gt;
:&amp;lt;code&amp;gt;on/off/state/suchmuster1/suchmuster2&amp;lt;/code&amp;gt;, wobei die letzten drei Angaben optional sind.&lt;br /&gt;
&lt;br /&gt;
Funktion: Bei Ausführung des Befehls wird das Gerät &#039;on&#039; oder &#039;off&#039; geschaltet (on/off), Voraussetzung ist, dass der &#039;state&#039; dieses Gerätes auch den &#039;state on&#039; oder &#039;off&#039; annimmt. Sollte dieses nicht der Fall sein, so kann mit dem Feld &#039;state&#039; angegeben werden, in welchem Reading der aktuelle Status vorkommt und wie dieser lautet (suchmuster1/suchmuster2). Dieses &#039;state&#039; kann mehrere Angaben enthalten, das Vorkommen der Suchmuster ist aber Voraussetzung.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Delete_Delays (0:1) ===&lt;br /&gt;
Bewirkt das Löschen aller anstehende Timer (Delays) bei dem Auftreten eines erneuten, passenden Events. Bei der Option &#039;0&#039; bleiben bereits gesetzte Delays aus einem vorherigen, getriggertem Event erhalten und werden ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1)&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Devicecmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz liefern (bei Abfrage set DEVICE ?).&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Webcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut Webcmd hinterlegt haben. Die in Webcmd hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten.&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Activate_MSwitchcmds (0:1) ===&lt;br /&gt;
Fügt jedem vorhandenen Device as Attribut &#039;MSwitchcmd&#039; hinzu.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_MSwitchcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut MSwitchcmds hinterlegt haben. Die in MSwitchcmds hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten. Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr Angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Lock_Quickedit (0:1) ===&lt;br /&gt;
Voreinstellung für die Auswahlliste &#039;Affected Devices&#039;. Bei der Option (1) ist diese voreingestellt gesperrt und kann nur über einen zusätzlichen Button geändert werden. Da es sich hier um ein Feld mit der Möglichkeit einer Mehrfacheingabe handelt handelt ist die Voreinstellung 1, um versehentliche nicht gewünschte Änderungen zu vermeiden (Auswahl einer Option ohne &#039;Strg&#039; bewirkt das löschen aller bereits gesetzten Optionen).&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay (0:10:20:30:60) ===&lt;br /&gt;
Diese Einstellung beeinflusst den Start von MSwitch nach einem FHEM Start. MSwitch ignoriert für die angegebene Zeit in Sekunden alle eingehenden Events um u.a. Startverzögerungen zu vermeiden. Bei nicht gesetztem Attribut gilt hier eine Zeit von 30 Sekunden. Diese sollte auch nur in Ausnahmefällen bzw. bei besonderem Bedarf geändert werden.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (30).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Ignore_Types ===&lt;br /&gt;
Beinhaltet eine Liste von Device&#039;&#039;typen&#039;&#039;, die in den Auswahllisten &#039;&#039;nicht&#039;&#039; dargestellt werden. Hier ist es sinnvoll, Devicetypen einzutragen, die in aller Regel nicht geschaltet werden oder nicht geschaltet werden können, um die Auswahllisten übersichtlicher zu halten. Einzelne Devicetypen sind durch Leerzeichen zu trennen.&lt;br /&gt;
&lt;br /&gt;
Voreinstellung: notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe kann hier in 2 Arten getätigt werden:&lt;br /&gt;
# eine Liste von devicetypen.&lt;br /&gt;
# Angabe einer devspec z.B. &amp;quot;TYPE=watchdog&amp;quot;. Hier ist zu beachten, dass in diesem Fall alle Geräte in die Ignoreliste einbezogen werden, die NICHT der devspec entsprechen. Weiterhin muss die devspec in Anführungszeichen gesetzt werden!&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Trigger_Filter ===&lt;br /&gt;
Beinhaltet eine Liste von Events, die bei eingehenden Events unberücksichtigt bleiben. Diese werde dann auch nicht gespeichert.&lt;br /&gt;
&lt;br /&gt;
Hier kann mit Wildcards (*) gearbeitet werden. Einzelne Events sind durch Komma &#039;,&#039; zu trennen.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (keine).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Wait (sec)===&lt;br /&gt;
Bei gesetztem Attribut (Zeit in Sekunden) nimmt Das MSwitch Device für den eingestellten Zeitraum keine Befehle mehr entgegen und ignoriert eingehende Events&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Event_Id_Distributor ===&lt;br /&gt;
Dieses Attribut hat nur dann eine Funktion, wenn auch das Attribut &#039;MSwitchExpert&#039; auf &#039;1&#039; gesetzt ist.&lt;br /&gt;
Hier können verschiedene auslösende Events auf Aktionen mit angegebenen IDs umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Sollte bei den &#039;trigger details :&#039; in einem Zweig ( cmd1 ) z.B. auf mehrere Events getriggert werden ( regex z.B. state:(on|off) ) so werden für beide Events jeweils der Zweig &#039;cmd1&#039; - alle  Aktionen ohneID - ausgeführt. Durch entsprechende Einträge kann für entsprechende Events auf eine Aktion umgeleitet werden, für die eine ID definiert ist. Die Syntax lautet:&lt;br /&gt;
:&amp;lt;code&amp;gt;state:on=&amp;gt;cmd1 ID 1,2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden bei auslösendem Event &#039;state:on&#039; nur die Aktionen aus cmd1 mit den IDs 1 und 2 ausgeführt. Mehrere Angaben sind durch new Line zu trennen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Selftrigger_always (0,1)===&lt;br /&gt;
(dieses Attribut steht ab Modulversion 2.5 zur Verfügung)&lt;br /&gt;
&lt;br /&gt;
Die Aktivierung dieses Attributes (1) bewirkt, dass alle SET Aktionen des Devices einen (internen) Event auslösen, auf die das Device selber reagiert. Diese Option kann zusätzlich zu einem vorhandenen Trigger aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Diese Events sind lediglich Device intern, d.h es werden keine Modulübergreifenden Events ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Auftretende und auswertbare interne Events haben immer folgendes Format und können darüber ausgewertet werden.&lt;br /&gt;
&lt;br /&gt;
MSwitch_Self:aktion:wert &lt;br /&gt;
MSwitch_Self:pct:100&lt;br /&gt;
&lt;br /&gt;
Es werden nur interne Events für set-Aktionen ausgelöst, die im Attribut setlist hinterlegt sind.&lt;br /&gt;
&lt;br /&gt;
Als weitere Besonderheit unterliegen diese internen Events nicht dem &#039;wait&#039; Befehl/Attribut.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Mode (Notify,Full,Toggle,Dummy)===&lt;br /&gt;
Schaltet das Modul zwischen verschiedenen Modi um, mit entsprechend angepasster Weboberfläche.&lt;br /&gt;
&lt;br /&gt;
==== Notify ====&lt;br /&gt;
Das Device kann nicht manuell umgeschaltet werden. Es gibt nur zwei ausführbare Zweige (execute &#039;cmd1&#039; commands und execute &#039;cmd2&#039; commands). Der Status des Devices wird nicht als &#039;on&#039; oder &#039;off&#039; angezeigt, sondern lediglich als &#039;active&#039;&lt;br /&gt;
&lt;br /&gt;
Dieser Mode ist am ehesten mit einem Notify zu Vergleichen.&lt;br /&gt;
&lt;br /&gt;
==== Full ====&lt;br /&gt;
Es stehen alle Funktionen zur Verfügung.&lt;br /&gt;
==== Toggle ====&lt;br /&gt;
Sehr vereinfachter Mode. Es stehen keine verschiedenen Zweige zur Verfügung. Hier ist das Device manuell schaltbar und wird bei jedem definierten Event &#039;Umgeschaltet&#039;, entsprechend definierte Befehle für &#039;cmd1&#039; oder &#039;cmd2&#039; werden ausgeführt.&lt;br /&gt;
==== Dummy====&lt;br /&gt;
ACHTUNG: Funktionsänderung mit V2.61&lt;br /&gt;
&lt;br /&gt;
Der Mode &#039;Dummy&#039; ist ein eingeschränkter Modus. &lt;br /&gt;
Dieser bietet die Funktionalität eines Dummys kombiniert mit der Funktionalität eines Notifys und kann somit die gerne genutzte Kombination Dummy-Notify gegen ein Device ersetzen.&lt;br /&gt;
&lt;br /&gt;
Achtung: Devices die einmal in dem Modus &#039;Dummy&#039; gesetzt wurden können nicht wieder in einen anderen Mode geschaltet werden ! &lt;br /&gt;
&lt;br /&gt;
Der Dummy-Mode kann nur in einem neu angelegtem, leeren MSwitch aktiviert werden. Sobald ein angelegtes MSwitch einmal verändert wurde (modify trigger etc.) ist ein Umschalten nicht mehr möglich und die Option nicht mehr verfügbar.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Condition_Time (0,1)===&lt;br /&gt;
In der Grundeinstellung (0) werden für das zeitgesteuerte Schalten keine definierten Conditionen im Feld &#039;Trigger condition&#039; überprüft, sondern die Schaltbefehle werden in jedem Fall ausgeführt. Mit der Einstellung (1) wird diese Überprüfung auch für zeitgesteuerte Befehle zugeschaltet.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Time (HH:MM:SS-HH:MM:SS)===&lt;br /&gt;
Bei Aktivierung wird vor jedem Ausführen eines verzögerten Befehls ( Delay ) eine Zufallszeit generiert, die im Rahme der hier angegebenen Zeitspanne liegt. Auf diese Zufallszahl kann in den Delays zugegriffen werden, durch die Angabe &#039;[random]&#039; statt einer direkten Zeitangabe. Bei nicht gesetztem Attribut ergibt die Angabe von &#039; [random] &#039; hier immer &#039;00:00:00&#039;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Number ===&lt;br /&gt;
Bei Aktivierung dieses Attributes (der Inhalt kann einen beliebige Zahl sein) werden vom Device 2 Readings angelegt (Device:RandomNr) und (Device:RandomNr1). RandomNr wird vor jedem Ausführen eines Befehls aktualisiert und neu generiert, d.h wenn ein MSwitch Device mehrere Geräte schaltet, wird (auch in einem Durchgang) vor jedem Befehl dieses Reading neu gesetzt. RandomNr1 wird lediglich bei Ausführung des MSwitch Devices einmal neu gesetzt, d.h. nicht vor jedem Befehl der ausgeführt wird.&lt;br /&gt;
Die Readings werden mit einer Zufallszahl zwischen 0 und dem hier eingestellten Wert gesetzt.&lt;br /&gt;
&lt;br /&gt;
Auf diese Readings kann in jeder Condition mit z.B. &#039;[$NAME:ReadingNr1] = 1&#039; zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
D.h., das in der Condition angegebene Reading ( [$NAME:ReadingNr1] ) muss in diesem Fall den Wert 1 angenommen haben, ansonsten wird der Befehl nicht ausgeführt. &lt;br /&gt;
Der Befehl wird somit nur mit einer Wahrscheinlichkeit von 1 zu ( gesetzter Wert im Attr. ) ausgeführt.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Reset_EVT_CMD1(2)_COUNT ===&lt;br /&gt;
Bei Aktivierung dieses Attributes steht in den Readings das Reading &#039;EVT_CMD1_COUNT&#039; bzw. &#039;EVT_CMD2_COUNT&#039; zur Verfügung. Dieses kann in den Conditions genutzt werden, um z.B. nur bei jedem x-ten Eintreffen eines auslösenden Events einen Befehl auszuführen. Bei jedem Eintreffen eines gültigen Events werden die Zähler um 1 erhöht (für den jeweiligen Zweig). &lt;br /&gt;
Ist hier der Wert &#039;0&#039; eingetragen, wird der Zähler fortlaufend (endlos) erhöht. Wird ein Wert größer 0 eingetragen, wird der Zähler mit Erreichen dieses Wertes automatisch wieder auf Null gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit Löschen dieses Attributes werden die entsprechenden Readings ebenfalls gelöscht.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Safemode (0:1)===&lt;br /&gt;
Bietet einen (gewissen) Schutz vor falschen Konfigurationen und somit entstehenden Endlosschleifen.&lt;br /&gt;
Bei aktiviertem Attribut (1) erkennt das Modul Endlosschleifen eines Devices und beendet diese.&lt;br /&gt;
&lt;br /&gt;
In diesem Fall erfolgt ein Logeintrag und das Device wird per Attribut auf &#039;Disabled&#039; gesetzt.&lt;br /&gt;
Es wird ein letztes Event generiert, auf das reagiert werden kann:&lt;br /&gt;
:&amp;lt;code&amp;gt;2018-05-31 09:39:21 MSwitch &amp;lt;NAME&amp;gt; Safemode: on&amp;lt;/code&amp;gt;&lt;br /&gt;
Im Webinterface erfolgt bei betroffenem Device ein entsprechender Hinweis.&lt;br /&gt;
&lt;br /&gt;
In der Grundkonfiguration ist dieses Attribut nicht gesetzt, es empfiehlt sich aber, bei neuen (komplizierten) Devices, dieses - zumindest anfänglich - zu aktivieren.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Read_Log(0:1)===&lt;br /&gt;
Ermöglicht den Zugriff auf das Logfile als Trigger.&lt;br /&gt;
&lt;br /&gt;
Hier gibt es mehrere Konfigurationsmöglichkeiten:&lt;br /&gt;
* Bei aktiviertem Attribut enthält die Auswahl des Triggerdevices die Option &#039;LOGFILE&#039;. Bei dieser Auswahl werde alle Logeinträge erkannt und in ein internes Event umgewandelt, auf das regiert werden kann.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl &#039;GLOBAL&#039; im &#039;Trigger_Device&#039; wird auf ALLE Events und alle Logeinträge reagiert.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl eines bestimmten Devices im &#039;Trigger_Device&#039; wird auf alle Events  und auf alle Logeinträge des gewählten Devices reagiert. Hier ist zu beachten, dass FHEM mir keine Möglichkeit bietet, wirklich herauszufinden, welches Device denn nun einen Logeintrag generiert hat. D.h., dieses wird vom Vorhandensein des Namens im Logeintrag abhängig gemacht und MSwitch reagiert nur dann auf einen Logeintrag, wenn der Name des Devices in diesem Eintrag vorhanden ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Help(0:1)===&lt;br /&gt;
Schaltet Hilfebuttons zu den einzelnen Eingabefeldern an oder aus.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Comments(0:1)===&lt;br /&gt;
Schaltet Kommentarfelder zu den einzelnen &#039;affected_devices an.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_generate_Events(0:1)===&lt;br /&gt;
Reduziert bei Einstellung &#039;1&#039; die vom MSwitch-Devices erzeugten Events auf ein absolutes Minimum. Insbesondere bei Verwendung von &#039;MSwitch_Read_Log&#039; zu empfehlen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay ===&lt;br /&gt;
Bestimmt die Verzögerungszeit des MSwitches nach FHEM-Start in Sekunden. In diesem Zeitraum reagiert das ??Event??(Red: ist hier &amp;quot;Device&amp;quot; gemeint?) nicht auf Events. Die Vorgabe ist hier zehn Sekunden. Diese wird auch dann angenommen, wenn das Attribut nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Inforoom ===&lt;br /&gt;
Mit diesem Attribut wird die Raumansicht eines mit dem Attribut bestimmten Raumes verändert. Dadurch sollen die wichtigsten Informationen aller MSwitch-Devices auf eine Seite dargestellt werden. Zur Nutzung sollten alle MSwitch-Devices (zusätzlich) in einen Raum sortiert werden und dieser Raum im Attribut eingestellt werden.&lt;br /&gt;
&lt;br /&gt;
Wichtig: Eine Änderung dieses Attributes bewirkt immer eine Änderung dieses Attributes in &#039;&#039;allen&#039;&#039; MSwitch devices: Es muss nur in einem Device gesetzt oder gelöscht werden um alle Devices zu erfassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
MSwitch_Screen_1.png|Raumansicht des Raumes MSwitch mit gesetztem Attribut &#039;MSwitch&#039;&lt;br /&gt;
MSwitch_Screen_2.png|Raumansicht des Raumes MSwitch ohne gesetztes Attribut&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es werden folgende Informationen bereitgestellt:&lt;br /&gt;
* Infobutton zeigt den im Device gespeicherten Textes des Attributes &#039;comment&#039;&lt;br /&gt;
* Device und Events, die das Device triggern&lt;br /&gt;
* Zeiten, zu denen verschiedene Zweige des Devices ausgeführt werden&lt;br /&gt;
* Devices, die durch das MSwitch Device geschaltet werden&lt;br /&gt;
* State des Devices&lt;br /&gt;
&lt;br /&gt;
== Integrierte Funktionen ==&lt;br /&gt;
&lt;br /&gt;
=== Average ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
=== Tendency ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[TEND&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;Mindestwert&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[TEND2:countdown] &amp;gt; 2&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Es wird jeweils der Durchschnitt von 2 Wertepaaren gebildet. In diesem Fall werden die letzten 4 Werte herangezogen.&amp;lt;br&amp;gt;&lt;br /&gt;
Paar 1 = Aktueller und letzter Wert, Paar 2 = Die 2 vorherigen Werte.&amp;lt;br&amp;gt;&lt;br /&gt;
Bei TEND3 werden die letzten 6 Werte zur Paarbildung genutzt.&lt;br /&gt;
&lt;br /&gt;
Mindestwert:&lt;br /&gt;
Der Wertunterschied zwischen den Wertepaaren, der minimal erreicht sein muss, um eine Tendenz zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Rechenzeichen (&amp;gt;&amp;lt;):&lt;br /&gt;
Dieses ist hier nicht als Rechenzeichen zu werten, sonder als Tendenz-Anzeige. ( &amp;lt; es wird nach fallender Tendenz gesucht / &amp;gt; sucht nach steigender Tendenz).&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolgt einmalig bei Erkennung der gesuchten Tendenz.&lt;br /&gt;
Danach erfolgt keine Schaltung mehr, solange bis eine Tendenz-Umkehr erfolgt ist.&lt;br /&gt;
Erst dann erfolgt wieder eine Schaltung bei erneuter Tendenz-Umkehr in gesuchte Richtung.&lt;br /&gt;
&lt;br /&gt;
=== Difference ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[DIFF&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;differenz&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[DIFF2:countdown] &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Gespeicherter Wert (in diesem Fall der vorletzte).&lt;br /&gt;
&lt;br /&gt;
Differenz:&lt;br /&gt;
Geforderter Differenz zwischen aktuellem und vorletztem Wert.&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolg wenn diese Bedingung &#039;wahr&#039; ist.&lt;br /&gt;
&lt;br /&gt;
Folgende Readings werden zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
DIFFERENCE (true/false) - Schaltbedingung erkannt ja/nein&lt;br /&gt;
&lt;br /&gt;
DIFFDIRECTION (up/down) - Richtung der erkannten Bedingung (steigend/fallend)&lt;br /&gt;
&lt;br /&gt;
=== Increase ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
== Tipps, Tricks, Kurzbeispiele ==&lt;br /&gt;
Wird stetig ergänzt .&lt;br /&gt;
&lt;br /&gt;
=== Blinken - Falls nicht im Device vorhanden ===&lt;br /&gt;
[[Datei:MSwitch MSwitchblink.png|center|704px]]&lt;br /&gt;
&amp;lt;br clear=all&amp;gt;&lt;br /&gt;
Lässt ein beliebiges Device 5 mal togglen, mit einem Intervall von 0.5 Sekunden (Blinkzeit somit 2,5 Sekunden)&amp;lt;br&amp;gt;&lt;br /&gt;
Die MSwitchtoggle-Funktion muss per ATTR aktiviert werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Die Repeatfunktion ist nur im Expertmode verfügbar, auch per ATTR einstellbar.&lt;br /&gt;
&lt;br /&gt;
=== Linearschalter ===&lt;br /&gt;
Umsetzung eines Linearschalters mit MSwitch.&lt;br /&gt;
&lt;br /&gt;
Eingang: Beliebiges Reading als numerischer Wert.&lt;br /&gt;
&lt;br /&gt;
Ausgang: Wird entsprechend Linear / oder umgekehrt Linear zum Eingang geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgend die Rawdefinition des MSwitchdevices und zweier Dummys (selbsterklärend)&lt;br /&gt;
&lt;br /&gt;
Alle Devices werden im Raum Lineartest angelegt, die Dummy müssen zuerst angelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod linearausgang dummy&lt;br /&gt;
attr linearausgang room Lineartest&lt;br /&gt;
attr linearausgang setList state:slider,0,1,100&lt;br /&gt;
attr linearausgang webCmd state&lt;br /&gt;
setstate linearausgang state 57&lt;br /&gt;
setstate linearausgang 2018-06-06 18:06:12 state state 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod lineareingang dummy&lt;br /&gt;
attr lineareingang room Lineartest&lt;br /&gt;
attr lineareingang setList state:slider,0,1,15000&lt;br /&gt;
attr lineareingang webCmd state&lt;br /&gt;
setstate lineareingang 6422&lt;br /&gt;
setstate lineareingang 2018-06-06 18:06:12 state 6422&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod Linearschalter MSwitch lineareingang  # linearausgang FreeCmd&lt;br /&gt;
attr Linearschalter MSwitch_Debug 0&lt;br /&gt;
attr Linearschalter MSwitch_Delete_Delays 1&lt;br /&gt;
attr Linearschalter MSwitch_Expert 0&lt;br /&gt;
attr Linearschalter MSwitch_Extensions 0&lt;br /&gt;
attr Linearschalter MSwitch_Help 0&lt;br /&gt;
attr Linearschalter MSwitch_Ignore_Types notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
attr Linearschalter MSwitch_Include_Devicecmds 1&lt;br /&gt;
attr Linearschalter MSwitch_Include_MSwitchcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Include_Webcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Inforoom MSwitch&lt;br /&gt;
attr Linearschalter MSwitch_Lock_Quickedit 1&lt;br /&gt;
attr Linearschalter MSwitch_Mode Notify&lt;br /&gt;
attr Linearschalter room Lineartest&lt;br /&gt;
&lt;br /&gt;
setstate Linearschalter active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:03:50 .Device_Affected FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:04:35 .Device_Affected_Details FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 );;my $emin=0;;my $emax=15000;;my $amin=100;;my $amax=0;;$eingang = $emin if $eingang &amp;lt; $emin;;$eingang = $emax if $eingang &amp;gt; $emax;;my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin;;readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 );;},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter:to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 .Device_Events no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .First_init done&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_on *&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_condition &lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_on no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_time &lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .V_Check V 0.3&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVENT state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTFULL lineareingang:state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART1 lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART2 state&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART3  6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 Exec_cmd set linearausgang state [Linearschalter:to_set]&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 Trigger_device lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 Trigger_log off&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 last_event state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:39:56 state active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 to_set 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
MSwitch -Configfile (bei Bedarf)&lt;br /&gt;
&amp;lt;pre&amp;gt;#V V1.54&lt;br /&gt;
#S .Device_Affected -&amp;gt; FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
#S .Device_Affected_Details -&amp;gt; FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 )[S]my $emin=0[S]my $emax=15000[S]my $amin=100[S]my $amax=0[S]$eingang = $emin if $eingang &amp;lt; $emin[S]$eingang = $emax if $eingang &amp;gt; $emax[S]my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin[S]readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 )[S]},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter.to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
#S .Device_Events -&amp;gt; no_trigger&lt;br /&gt;
#S .First_init -&amp;gt; done&lt;br /&gt;
#S .Trigger_Whitelist -&amp;gt; undef&lt;br /&gt;
#S .Trigger_cmd_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_cmd_on -&amp;gt; *&lt;br /&gt;
#S .Trigger_condition -&amp;gt; &lt;br /&gt;
#S .Trigger_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_on -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_time -&amp;gt; &lt;br /&gt;
#S .V_Check -&amp;gt; V 0.3&lt;br /&gt;
#S Trigger_device -&amp;gt; lineareingang&lt;br /&gt;
#S Trigger_log -&amp;gt; off&lt;br /&gt;
#S last_event -&amp;gt; state: 6422&lt;br /&gt;
#S state -&amp;gt; active&lt;br /&gt;
#A MSwitch_Ignore_Types -&amp;gt; notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
#A MSwitch_Include_MSwitchcmds -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Debug -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Help -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Devicecmds -&amp;gt; 1&lt;br /&gt;
#A MSwitch_Extensions -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Webcmds -&amp;gt; 0&lt;br /&gt;
#A room -&amp;gt; Lineartest&lt;br /&gt;
#A MSwitch_Inforoom -&amp;gt; MSwitch&lt;br /&gt;
#A MSwitch_Expert -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Lock_Quickedit -&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Thread über das Modul im {{Link2Forum|Topic=86199|LinkText=FHEM Forum}}&lt;br /&gt;
* {{Link2Forum|Topic=100119|Message=936495|LinkText=Gäste-WLAN der Fritzbox auswerten und Login per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=86199|Message=930133|LinkText=Schalten von vier Kanälen mit einem MSwitch-Device}}&lt;br /&gt;
* {{Link2Forum|Topic=99219|Message=926652|LinkText=Batterie-Überwachung. 1xTäglich per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=101091|Message=945389|LinkText=Licht (Alarm) in einem bestimmten Zeitraum schalten}}&lt;br /&gt;
* {{Link2Forum|Topic=100949|Message=944284|LinkText=Über Dummy-Schalter ein Timer (EIN/AUS) aktivieren}}&lt;br /&gt;
* {{Link2Forum|Topic=103083|Message=967710|LinkText=Ladezeit von Akku ermitteln u. Steckdose entsprechend schalten}}&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31477</id>
		<title>MSwitch</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31477"/>
		<updated>2019-11-01T20:00:25Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* MSwitch_Selftrigger_always (0,1) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[MSwitch]] ist ein Hilfsmodul, welches das Event- und/oder zeitgesteuerte Schalten von mehreren Devices oder das Ausführen von benutzerdefinierten Befehlssequenzen erlaubt.&lt;br /&gt;
&lt;br /&gt;
Die Stärke bzw. das Unterscheidungsmerkmal dieses Moduls liegt in der Konfigurierbarkeit über ein Webinterface. Diese Konfiguration kann jederzeit geändert oder erweitert werden. &lt;br /&gt;
&lt;br /&gt;
Byte09: &#039;&#039;Die Grundidee zu MSwitch kam mir, weil ich bei der Arbeit mit FHEM für meinen Geschmack zu viele Module für die verschiedenen Aufgaben brauchte - zu allem Überfluss alle mit unterschiedlicher Syntax. Zwar ist DOIF hiervon ausgenommen (da hiermit wohl auch fast jede Aufgabe lösbar ist), aber ich konnte mich leider nicht daran gewöhnen und somit wurde jedes DOIF für mich zu einem echten Projekt. Was ich wollte war ein Modul, mit dem ich alles erledigen kann. Daher entschloss ich mich schon nach fast einem knappen Jahr FHEM-Nutzung mein eigenes Modul zu schreiben, welches diese Anforderung erfüllt. MSwitch beinhaltet die Funktionalität aller bisherigen Hilfsmodule wie z.B. Notify, Doif, Watchdog, Dummy,( ab Modulversion 2.2 auch Sequenz ) es lassen sich all deren Funktionen umsetzen.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;MSwitch wird permanent - vorrangig nach meinen Bedürfnissen - weiterentwickelt, gerne nehme ich aber auch Anregungen von anderen Nutzern auf.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=MSwitch&lt;br /&gt;
|ModType=h&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=98_MSwitch.pm&lt;br /&gt;
|ModOwner=Byte09}}&lt;br /&gt;
&lt;br /&gt;
== Grundsätzliche Überlegungen ==&lt;br /&gt;
Um das Modul zu nutzen, muss man zuerst folgende Fragen beantworten:&lt;br /&gt;
&lt;br /&gt;
* Welches Gerät soll auslösen oder zu welcher Zeit soll eine Auslösung erfolgen.&lt;br /&gt;
: Dies ist der Trigger. Jedes Event aus dem Eventmonitor kann als Trigger dienen. Will man mehrere Geräte als gleichzeitige Auslöser betreiben, so muss das Device GLOBAL gewählt und die entsprechenden Geräte angegeben werden (dies erzeugt höhere Systemlast und ist nur im Expert-Modus verfügbar). Weiterhin kann auch zu fest definierten Zeiten, Zufallszeiten oder Intervallen, unabhängig von einem Trigger, geschaltet werden; auch eine Kombination beider Varianten ist möglich. Diese Einstellungen erfolgen im ersten Teil des Webinterfaces.&lt;br /&gt;
&lt;br /&gt;
* Welche Bedingungen sollen bei Auslösung erfüllt sein?&lt;br /&gt;
: Wenn diese Bedingungen erfüllt sind, werden Kommandos ausgelöst. Die Bedingungen werden im zweiten Teil des Webinterfaces eingegeben. Dabei unterscheidet das Modul zwischen zwei Kommando-Kanälen (cmd1 und cmd2) und den dazugehörigen Geräten.&lt;br /&gt;
&lt;br /&gt;
* Welche Kommandos sollen ausgelöst werden?&lt;br /&gt;
: Im dritten Teil des Webinterfaces werden dann die konkreten Kommandos eingegeben. Typischerweise wählt man dabei aus einer Liste der Kommandos aus, die die zugehörigen Geräte insgesamt aufweisen (also so, wie man auf den Geräteseiten selber Kommandos auswählt). Es gibt zudem ein so genanntes FreeCmd, das ein Geräteunabhängiges Kommando zulässt, beispielsweise reinen Perl-Code.&lt;br /&gt;
&lt;br /&gt;
* Welche weiteren Bedingungen sollen noch gelten?&lt;br /&gt;
: Hier sind Ereignisgesteuerte wie auch Zeitgesteuerte Bedingungen möglich. Diese Bedingungen werden auch in dem dritten Teil des Webinterfaces eingetragen. So sind Verzögerungen und Wiederholungen und weitere Bedingungen möglich.&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen, Installation und Grundbefehle ==&lt;br /&gt;
Das MSwitch-Modul ist ohne weitere Voraussetzungen nutzbar und wird derzeit in der Version 2.08 über FHEM Update verteilt. &lt;br /&gt;
&lt;br /&gt;
=== Definition und Einrichtung ===&lt;br /&gt;
Mit Hilfe von MSwitch kann man mehrere Devices gleichzeitig schalten. Diese Schaltungen befinden sich in zwei möglichen Zweigen bei MSwitch. Dabei unterscheidet man im Modul zwischen den beiden Kommandos cmd1 und cmd2. Die zu einem Kommando gehörenden Geräte werden wir auch Zweig nennen. Die einzelnen Devices jedes Zweiges können mit weiteren Schaltbedingungen versehen werden (zeit- oder ereignisgesteuert). &lt;br /&gt;
&lt;br /&gt;
Folgende Möglichkeiten zum definieren des MSwitch Devices stehen zur Verfügung:&lt;br /&gt;
:&amp;lt;code&amp;gt;define &amp;lt;name&amp;gt; MSwitch&amp;lt;/code&amp;gt;&lt;br /&gt;
Es wird ein leeres Device angelegt, das dann komplett über das Webinterface konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das define eines MSwitch Devices generiert lediglich eine &#039;leere Hülle&#039;. Alle relevante Einstellungen werden in Readings und/oder Hashes gespeichert. Daher stehen relevanten Daten &#039;&#039;nicht&#039;&#039; in der fhem.cfg! Vielmehr finden sich diese Daten in der Datei fhem.save (die Speicherung erfolgt durch den Befehl Fhemsave).&lt;br /&gt;
&lt;br /&gt;
=== set-Befehle ===&lt;br /&gt;
Es sind derzeit die folgenden set-Befehle implementiert.&lt;br /&gt;
&lt;br /&gt;
==== set active ====&lt;br /&gt;
Setzt das Device in den Status &#039;active&#039;.&lt;br /&gt;
&lt;br /&gt;
==== set inactive ====&lt;br /&gt;
Setzt das Device in den Status &#039;inactive&#039;, es werden keine Befehle mehr ausgeführt. Dieser Status entspricht dem Attribut &#039;disable&#039;, ist aber nicht mit dem roten Fragezeichen (fhem save) verbunden.&lt;br /&gt;
&lt;br /&gt;
==== set on/off [&amp;lt;parameter&amp;gt;]====&lt;br /&gt;
Setzt das Device in den Status &#039;on&#039; oder &#039;off&#039;. Alle Befehle der &#039;on/off-Zweige&#039; werden ausgeführt.&lt;br /&gt;
Optional kann den Befehlen &#039;on&#039; und &#039;off&#039; ein weiterer Parameter mit übergeben werden. Dieser wird im Reading &#039;Parameter&#039; hinterlegt und es kann sofort in &#039;Freecmds&#039; oder &#039;Conditions&#039; darauf zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
==== set reload_timer ====&lt;br /&gt;
Alle gesetzten Timer werden gelöscht und neu berechnet.&lt;br /&gt;
&lt;br /&gt;
==== set change_renamed &amp;lt;oldname&amp;gt; &amp;lt;newname&amp;gt; ====&lt;br /&gt;
Sollten sich Devicenammen im ausführenden Teil geändert habe (affected Devices, Conditions, etc.) so kann das MSwitch mit diesem Befehl angepasst werden, ohne alle Einstellungen neu einstellen zu müssen.&lt;br /&gt;
&lt;br /&gt;
==== set exec_cmd1 / set exec_cmd1 ID [&amp;lt;ID&amp;gt;] ====&lt;br /&gt;
Bewirkt das sofortige Ausführen des entsprechenden Befehlszweiges. Bei Angabe einer ID werden nur die Befehle mit der entsprechenden ID ausgeführt.&lt;br /&gt;
&lt;br /&gt;
==== set MSwitch_backup ====&lt;br /&gt;
Erstellt eine Backup-Datei aller MSwitch Devices unter ./fhem/MSwitch_backup.cfg.&lt;br /&gt;
&lt;br /&gt;
Daten dieser Datei können im Bedarfsfall für einzelne oder gleichzeitig alle MSwitch Devices wieder zurückgespielt (hergestellt) werden.&lt;br /&gt;
&lt;br /&gt;
==== set del_delays ====&lt;br /&gt;
Löscht alle anstehenden, verzögerten Befehle (delays).&lt;br /&gt;
&lt;br /&gt;
==== set reset_cmd_count:1,2 ====&lt;br /&gt;
Löscht das entsprechende EVT_CMD_COUNT - Reading (entspricht Rückstellung auf &#039;0&#039;).&lt;br /&gt;
&lt;br /&gt;
==== set fakeevent [&amp;lt;device&amp;gt;]:&amp;lt;reading&amp;gt;:&amp;lt;arg&amp;gt; ====&lt;br /&gt;
Beispiel: &amp;lt;device&amp;gt; fakeevent state:on&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ob der Name (&amp;lt;device&amp;gt;) angegeben werden muss, oder nicht, ist abhängig davon, ob auf ein einzelnes Device, oder GLOBAL getriggert wird. Bei GLOBALEN Triggern muss das Device mit angegeben werden. Wird auf ein Device getriggert, so wird das Device automatisch gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit diesem Befehl kann das MSwitch Device neu getriggert werden, indem hier ein Event &#039;gefaked&#039; wird. Das MSwitch Device reagiert dann so, als wäre dieses Event vom getriggerten Gerät generiert worden. &lt;br /&gt;
&lt;br /&gt;
Dieses kann nötig sein, um z.B. einen Watchdog zu realisieren, in dem es nötig ist, dass sich das MSwitch Device mit einem bestimmten Event selber neu triggert - ggf. mit einem entsprechenden Delay (affected Device muss dafür u.A. des MSwitch Device selber sein).&lt;br /&gt;
&lt;br /&gt;
Es wird hierbei KEIN echtes Event generiert welches das System beeinflusst, sondern ausschließlich ein MSwitch-Interner Befehl umgesetzt!&lt;br /&gt;
&lt;br /&gt;
Bei dem Einsatz dieser Möglichkeit sollte das Attribut &#039;MSwitch_Safemode&#039; UNBEDINGT aktiviert sein, da &#039;Experimente&#039; hier schnell in einer Endlosschleife enden können, die nur durch ein Reboot unterbrochen werden kann. &lt;br /&gt;
&lt;br /&gt;
Ggf. werde ich hier sogar eine entsprechende Änderung vornehmen, dass dieser Befehl nur zur Verfügung steht, wenn Safemode aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
=== get-Befehle ===&lt;br /&gt;
==== get show_timer [&amp;lt;show&amp;gt;&amp;lt;delete&amp;gt;] ====&lt;br /&gt;
;Show&lt;br /&gt;
:Zeigt alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren.&lt;br /&gt;
;Delete&lt;br /&gt;
:Löscht alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren. Schaltbefehle basierend auf rein zeitabhängigen Angaben werden neu berechnet und gesetzt.&lt;br /&gt;
&lt;br /&gt;
==== get restore_MSwitch_data [&amp;lt;this_device&amp;gt;&amp;lt;all_devices&amp;gt;] ====&lt;br /&gt;
;this_device&lt;br /&gt;
:Stellt die Daten des Devices aus der Backupdatei wieder her, sofern diese in der Backupdatei gefunden werden (gesucht wird hier nach dem Namen des Devices).&lt;br /&gt;
;all_devices&lt;br /&gt;
:Stellt die Daten aller MSwitch Devices wieder her, sofern diese in der Backupdatei vorhanden sind. Diese Aktion kann einige Zeit in Anspruch nehmen und wird daher im Hintergrund (nonblocking) ausgeführt. Nach Beendigung erfolgt eine Benachrichtigung.&lt;br /&gt;
&lt;br /&gt;
Die Devices sind nach einem Restore funktionsfähig. Empfohlen wird ein Neustart von FHEM.&lt;br /&gt;
&lt;br /&gt;
==== get_config ==== &lt;br /&gt;
Zeigt die Konfigurationsdatei des MSwitchdevices an; diese kann in dem Fenster editiert werden. Das sollte nur von erfahrenen Usern getan werden! Im Normalfall sollte das Device nur über die Weboberfläche konfiguriert werden und eine falsche Konfiguration kann hier zu einem FHEM Absturz führen.&lt;br /&gt;
&lt;br /&gt;
==== get_support_info ==== &lt;br /&gt;
Öffnet ein Fenster mit einer formatierten Ansicht aller Einstellungen des Devices. Bei Supportanfragen sollte dieses immer mit geposted werden.&lt;br /&gt;
&lt;br /&gt;
==== get_MSwitch_preconf ====&lt;br /&gt;
Lädt vorkonfigurierte MSwitch-Devices. Diese Option ist nur dann vorhanden, wenn das Aktualisieren dieser vorkonfigurierten Devices im FHEM Update aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
Diese kann durch ein einmaliges Update erfolgen mit:&lt;br /&gt;
:&amp;lt;code&amp;gt;update all https://raw.githubusercontent.com/Byte009/MSwitch_Addons/master/controls_mswitchaddons.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Webinterface ==&lt;br /&gt;
MSwitch wird im Wesentlichen über das Webinterface eingerichtet. Wählt man das folgende Attribut&lt;br /&gt;
:&amp;lt;code&amp;gt;attr &amp;lt;name&amp;gt; MSwitch_Help 1&amp;lt;/code&amp;gt;&lt;br /&gt;
so wird im Modul selber eine sehr umfangreiche Hilfe angezeigt. Über das gesamte Webinterface hinweg erscheinen kleine Fragezeichen, die man anklicken kann und die beschreiben, was in dem jeweiligen Textfeld sinnvollerweise einzugeben ist bzw. was das Modul an dieser Stelle erwartet.&lt;br /&gt;
&lt;br /&gt;
Das Webinterface besteht aus vier Teilen. Änderungen in jedem Abschnitt müssen in dem jeweiligen Teil bestätigt werden und auch nur diese werden gespeichert. Bevor ein weiterer Teil bearbeitet wird, sollten Änderungen gespeichert werden, sie gehen sonst verloren.&lt;br /&gt;
&lt;br /&gt;
=== Trigger device/time ===&lt;br /&gt;
==== Trigger Device ====&lt;br /&gt;
In diesem Feld wird das Device ausgewählt, dessen Events eine Aktion auslösen sollen. Dazu werden alle verfügbaren Devices in einem Dropdownfeld angeboten.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es eine Auswahl &#039;GLOBAL&#039;, wenn das Attribut &#039;MSwitch_Expert&#039; gesetzt ist. Bei Auswahl dieser Option werden &#039;&#039;&#039;alle&#039;&#039;&#039; von FHEM generierten Events durch das MSwitch Device weiterverarbeitet, eine weitere Begrenzung der aktivierenden Events kann (und sollte) dann in einem folgenden Eingabefeld erfolgen, um die Systemlast zu reduzieren.&lt;br /&gt;
&lt;br /&gt;
==== Trigger Device Global Whitelist ====&lt;br /&gt;
Dieses Feld ist nur verfügbar, wenn als Trigger &#039;GLOBAL&#039; gewählt wurde.&lt;br /&gt;
&lt;br /&gt;
Hier kann die Liste eingehender Events weiter eingeschränkt werden. Es handelt sich um eine Whitelist, d.h., wenn es keine Einträge gibt, werden Events aller Devices verarbeitet. Sobald ein oder mehrere Einträge gemacht werden, werden nur noch Events der hier benannten Devices verarbeitet. Als Angabe können hier Devices benannt werden oder ganze DeviceTypen (z.B. TYPE=FS20). Mehrere Angaben sind durch Komma zu trennen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:MSwitchWebinterface1.png|400px|thumb|right|Webinterface, oben]]&lt;br /&gt;
Im gezeigten Beispiel wurde GLOBAL gewählt, weil nicht ein einzelnes Device, sondern eine Kombination aus zwei Geräten auslösen soll. Es werden also alle Ereignisse betrachtet, wobei die Whitelist dann auf die Devices Schlafzimmer (ein Temperaturmessgerät) und Schlafzimmerfenster (ein [[HM-Sec-SCo Tür-Fensterkontakt, optisch|optischer Kontakt]]) einschränkt. &lt;br /&gt;
&lt;br /&gt;
==== Trigger time ==== &lt;br /&gt;
Es besteht die Möglichkeit, das Modul (neben den Events) zu festen Zeiten auszulösen. Dann wären in die leer stehenden Zeilen bei &amp;quot;at&amp;quot; entsprechende Termine einzutragen. Zeitangaben erfolgen durch [STUNDEN:MINUTEN|TAGE], wobei die Tage von 1-7 gezählt werden (1 steht für Montag, 7 für Sonntag usw.). &lt;br /&gt;
Mehrere Zeitvorgaben können direkt aneinandergereiht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [17:00|1][18:30|23] den Trigger montags um 17 Uhr auslösen und dienstags sowie mittwochs um 18:30 Uhr.&lt;br /&gt;
Bei [00:10*20:00-21:00] würde der Schaltbefehl von 21 Uhr bis 21 Uhr alle 10 Minuten ausgeführt. Bei [?20:00-21:00] würde der Schaltbefehl zu einem zufälligen Zeitpunkt zwischen 20 und 21 Uhr ausgeführt.  [20:00|$we] bedeutet, dass nur am Wochenende um 20:00 geschaltet wird.&lt;br /&gt;
&lt;br /&gt;
==== Trigger conditions ====&lt;br /&gt;
Hier kann die Angabe von Bedingungen erfolgen, die zusätzlich zu dem triggernden Device erfüllt sein müssen.&lt;br /&gt;
Diese Bedingungen sind eng an DOIF-Syntax angelehnt. Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich.&lt;br /&gt;
&lt;br /&gt;
Wird in diesem Feld keine Angabe gemacht, so erfolgt der Schaltvorgang nur durch das triggernde Device ohne weitere Bedingungen.&lt;br /&gt;
&lt;br /&gt;
;Zeitabhängigkeit&lt;br /&gt;
:[19:10-23:00] - Trigger des Devices erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
;Readingabhängige Trigger&lt;br /&gt;
:[Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Trigger des Device erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
:Werden Readings mit Strings abgefragt (on,off,etc.), ist statt des Gleichheitszeichens &amp;quot;=&amp;quot; der Operator &amp;quot;eq&amp;quot; zu nutzen, der String muss in Anführungszeichen &amp;quot;&amp;quot; gesetzt werden.&lt;br /&gt;
;mehrere Beispiele&lt;br /&gt;
:[19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
:[19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
:[10:00-11:00|13] - schaltet Montag und Mittwoch zwischen 10 Uhr und 11 Uhr.&lt;br /&gt;
:[{ sunset() }-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
:{ !$we } löst den Schaltvorgang nur Werktagen an aus.&lt;br /&gt;
:{ $we } löst den Schaltvorgang nur an Wochenenden, Feiertagen aus.&lt;br /&gt;
&lt;br /&gt;
Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (beispielsweise würde dann am Mittwoch noch der Schaltvorgang erfolgen, obwohl als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
Bedingungen in diesem Feld gelten nur für auslösende Trigger eines Devices und haben keinen Einfluss auf zeitgesteuerte Auslöser.&lt;br /&gt;
&lt;br /&gt;
=== Trigger details ===&lt;br /&gt;
[[Datei:MSwitchWebinterface2.png|600px|thumb|right|Webinterface, Mitte]]&lt;br /&gt;
Während im obigen Feld das Device ausgewählt  werden konnte, wird hier das Ereignis festgelegt. Das Eingabefeld besteht aus mehreren Einzelfeldern.&lt;br /&gt;
&lt;br /&gt;
Im abgebildeten Fall wird cmd1 ausgelöst, wenn der Zustand des Schlafzimmerfenster-Sensors meldet, dass das Fenster offen ist. Cmd2 wird ausgelöst, wenn die Temperatur des Schlafzimmersensors unter einen bestimmten Wert fallen wird.&lt;br /&gt;
&lt;br /&gt;
==== execute &#039;cmd1/cmd2&#039;  ====&lt;br /&gt;
Hier kann  aus einer vorbelegten Dropdownliste ausgewählt werden, welches ankommende Event den entsprechenden Befehlszweig auslösen soll. In dieser Liste werden bei entsprechender Einstellung alle ankommenden Events eines vorher definierten Devices gespeichert. In einem weiteren Feld (siehe unten) können Events manuell zugefügt werden.&lt;br /&gt;
&lt;br /&gt;
==== Save incomming events ====&lt;br /&gt;
Bei Aktivierung dieser Option werden alle ankommenden Events des oben definierten Devices (oder Global) gespeichert und in entsprechenden Dropdownlisten angeboten.&lt;br /&gt;
&lt;br /&gt;
Da hier doch erhebliche Datenmengen anfallen können (je nach Device) wird empfohlen, diese Option nach der Konfiguration des Devices zu deaktivieren.&lt;br /&gt;
&lt;br /&gt;
==== add event ====&lt;br /&gt;
Hier besteht die Möglichkeit, unabhängig von der Option, ankommende Events automatisch zu speichern. Manuell Events anzulegen, die in den Dropdownliste zur Auswahl angeboten werden, ohne das entsprechendes Event erst vom Device geliefert werden muss.&lt;br /&gt;
&lt;br /&gt;
Es können mehrere Events gleichzeitig eingegeben werden, eine Trennung erfolgt durch &amp;quot; , &amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Hier ist zu unterscheiden, ob das gewählte triggernde Device ein einfaches Device ist oder ob der Trigger &#039;GLOBAL&#039; ist.&lt;br /&gt;
Bei triggernden Devices können Events in folgendem Formaten zugefügt werden:&lt;br /&gt;
&lt;br /&gt;
- *                                                    - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:wert   (z.b. state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:*      (z.b. state:* )                       - Aktion erfolgt auf die Events &amp;quot;state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:(wert1/wert2/wert3) (z.b. state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;state:left&amp;quot; oder &amp;quot;state:right&amp;quot; etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Falls auf &#039;GLOBALE&#039; Events getriggert wird, muss das auslösende Device vorangestellt werden:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
- *                                                           - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:wert   (z.b. device:state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;device:state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:*      (z.b. device:state:* )                       - Aktion erfolgt auf die Events &amp;quot;device:state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:(wert1/wert2/wert3) (z.b. device:state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;device:state:left&amp;quot; oder &amp;quot;devicestate:right&amp;quot; etc.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Device kann auch hier gegen &amp;quot;*&amp;quot; ersetzt werden (*:state:on). In diesem Fall erfolgt eine Aktion auf alle Events die z.B. &amp;quot;state:on&amp;quot; enthalten, egal welches Device triggert.&lt;br /&gt;
&lt;br /&gt;
==== test event ====&lt;br /&gt;
Dieses Feld wird angeboten, wenn entsprechende vom Triggerdevice gelieferte Events gespeichert wurden.&lt;br /&gt;
&lt;br /&gt;
Durch Auslösen dieser Funktion wird das Event simuliert und entsprechende definierte Aktionen ausgelöst. Diese Funktion dient ausschließlich zum Testen der eingestellten Konfiguration. Alle entsprechenden Befehle werden ausgeführt, als würde das Event real eintreffen.&lt;br /&gt;
&lt;br /&gt;
==== apply filter to saved events ====&lt;br /&gt;
Beschreibung folgt&lt;br /&gt;
&lt;br /&gt;
==== clear saved event ====&lt;br /&gt;
Es werden alle gespeicherten Events gelöscht.&lt;br /&gt;
&lt;br /&gt;
Ausnahme: Events, die als Trigger eingestellt sind, bleiben erhalten.&lt;br /&gt;
&lt;br /&gt;
=== Affected devices ===&lt;br /&gt;
[[Datei:MSwitch_Screen_5.png|mini|rechts|affected devices]]&lt;br /&gt;
Dieser Abschnitt beinhaltet die Auswahl der Devices, die auf ein Event reagieren sollen.&lt;br /&gt;
&lt;br /&gt;
In dem Auswahlfeld werden alle Devices angeboten, die eines der folgenden Kriterien erfüllen:&lt;br /&gt;
# Die Abfrage &amp;quot;set Device ?&amp;quot; liefert einen Befehlssatz&lt;br /&gt;
# Das Attribut &#039;webcmd&#039; des Devices enthält Einträge&lt;br /&gt;
# Das Attribut &#039;MSwitch_Activate_MSwitchcmds&#039; ist aktiviert und das Attribut &#039;MSwitchcmds&#039; des betreffenden Devices enthält einen Befehlssatz&lt;br /&gt;
&lt;br /&gt;
Einzige Ausnahme ist der erste Listeneintrag &#039;FreeCMD&#039;. Die Auswahl dieses Eintrages bietet später die Möglichkeit Befehle auszuführen, die nicht an ein Device gebunden sind. Der Code in einem FreeCmd kann entweder reiner FHEM-Code sein ( set device on ) oder reiner Perl-Code. Wenn es sich um reinen Perl-Code handelt, ist dieser in geschweifte Klammen zu setzen { Perl-Code }.&lt;br /&gt;
&lt;br /&gt;
=== Device actions ===&lt;br /&gt;
[[Datei:Webinterface3.png|mini|rechts|device_actions]]&lt;br /&gt;
Hier stellt man die auszuführenden Aktionen der eingestellten Devices ein. Im ersten Abschnitt oben befindet sich ein FreeCmd, mit dem beliebige Kommandos eingetragen werden können. Im abgebildeten Beispiel ist dies sogar selbst definierter Perl-Code (die Funktion DebianMail sendet eine Mail). &lt;br /&gt;
&lt;br /&gt;
==== MSwitch cmd1/cmd2:  ====&lt;br /&gt;
Man wählt den Befehl aus dem betreffenden Device aus. Bei freien Textfeldern (wie im Fall des FreeCmd) wird der Befehl eingegeben.&lt;br /&gt;
&lt;br /&gt;
Es werden alle verfügbaren Befehle des Devices zur Auswahl angeboten. Je nach Attribut-Einstellungen werden Einträge aus entsprechenden &#039;webcmds&amp;quot; oder &#039;MSwitchcmds&#039; einbezogen. In Abhängigkeit des Befehls stehen unter Umständen weitere Felder oder Widgets zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
05.04.2018 NEU: Auswahlfeld &#039;MSwitchtoggle&#039; -&amp;gt; Beschreibung wird noch ergänzt !&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 condition  ====&lt;br /&gt;
Mit diesem Feld kann die Ausführung des Befehls von weiteren Bedingungen abhängig gemacht werden. Bei der Abfrage von Readings nach Strings (on, off, etc.) ist statt &amp;quot;=&amp;quot; &amp;quot;eq&amp;quot; zu nutzen und der String muss in &amp;quot;x&amp;quot; gesetzt werden. Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
#Zeitabhängiges schalten: [19:10-23:00] - Schaltbefehl erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
#Readingabhängiges schalten [Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Schaltbefehl erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
&lt;br /&gt;
Soll nur an bestimmten Wochentagen geschaltet werden, muss eine Zeitangabe gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [10:00-11:00|13] den Schaltvorgang nur Montag und Mittwoch zwischen 10 Uhr und 11 Uhr auslösen. Hierbei zählen die Wochentage von 1-7 für Montag-Sonntag.&lt;br /&gt;
&lt;br /&gt;
Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich:&lt;br /&gt;
* [19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
* [19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
* [{sunset()}-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
* { !$we } löst den Schaltvorgang nur Werktagen aus&lt;br /&gt;
* { $we } löst den Schaltvorgang nur Wochenenden, Feiertagen aus&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung:&#039;&#039;&#039; Bei Anwendung der geschweiften Klammern zur Einleitung eines Perl Ausdrucks ist unbedingt auf die Leerzeichen hinter und vor der Klammer zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (zum Beispiel würde auch am Mittwoch noch der Schaltvorgang erfolgen, wenn als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
; $EVENT:&lt;br /&gt;
: Die Variable EVENT enthält den auslösenden Trigger, d.h. es kann eine Reaktion in direkter Abhängigkeit zum auslösenden Trigger erfolgen.&lt;br /&gt;
&lt;br /&gt;
[$EVENT] eq &amp;quot;state:on&amp;quot; würde den Kommandozweig nur dann ausführen, wenn der auslösende Trigger &amp;quot;state:on&amp;quot; war. Wichtig ist dieses, wenn bei den Triggerdetails nicht schon auf ein bestimmtes Event getriggert wird, sondern hier durch die Nutzung eines Wildcards (*) auf alle Events getriggert wird, oder auf alle Events eines Readings z.B. (state:*).&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 delay  ====&lt;br /&gt;
Ein Eintrag in diesem Feld führt zur verzögerten Ausführung des Befehls nach Eintreffen des Events. Dabei kann der Befehl ohne weitere Prüfung der Bedingung ausgelöst werden. Es ist aber auch möglich, dass die Bedingung bei Ausführung erneut geprüft wird. Die Zeitangabe muss im Format hh:mm:ss vorliegen.&lt;br /&gt;
&lt;br /&gt;
Statt einer unmittelbaren Zeitangabe kann hier auch ein Verweis auf ein Reading eines Devices erfolgen :&amp;lt;br&amp;gt;&lt;br /&gt;
[NAME.reading] des Devices -&amp;gt;z.B. [dummy.state]&lt;br /&gt;
&lt;br /&gt;
==== add action  ====&lt;br /&gt;
Mit diesem Button kann ein weiteres Eingabefeld für das entsprechende Device angelegt werden, um z.B. einen weiteren Befehl (ggf.) zeitverzögert auszuführen.&lt;br /&gt;
&lt;br /&gt;
==== delete this action  ====&lt;br /&gt;
Mit diesem Button wird der entsprechende Befehl für das Device gelöscht.&lt;br /&gt;
&lt;br /&gt;
==== check condition  ====&lt;br /&gt;
[[Datei:MSwitch_Screen_7.png|mini|rechts|check]]&lt;br /&gt;
Die angegebenen &#039;conditions&#039; werden in Zusammenhang mit ggf. ausgewählten Devices auf Syntax und Ergebnis geprüft. Es erfolgt eine Ausgabe des Prüfungsergebnisses.&lt;br /&gt;
&lt;br /&gt;
==== Repeat und Repeatdelay ====&lt;br /&gt;
Man kann mehrfache Wiederholungen erzwingen. Repeat gibt dabei an, wie oft das Kommando wiederholt wird (Anzahl). Repeatdelay gibt an, wie viel Sekunden zwischen einzelnen Wiederholungen liegen sollen.&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Folgende Attribute stehen zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Debug (0:1:2:3:4) ===&lt;br /&gt;
0 - Abgeschaltet&amp;lt;br&amp;gt;&lt;br /&gt;
1 - Schaltet Felder zum testen der Conditionstrings etc. an&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Alle ausgehenden Befehle werden nur simuliert und nicht ausgeführt. Es erfolgt eine Protokollierung in einer separaten Datei . Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Es erfolgt eine Protokollierung in einer separaten Datei . Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
4 - erweiterte Debugfunktion (nur für Entwicklung - wechselnde Funktion )&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Expert (0:1) ===&lt;br /&gt;
In der Liste der möglichen Trigger erscheint das Selectfeld &#039;GLOBAL&#039;. Dieses ermöglicht das Setzen eines Triggers auf alle Events und damit nicht nur auf einzelne Devices. In einem weiteren Feld kann eine weitere Selektion der triggernden Events erfolgen.&lt;br /&gt;
&lt;br /&gt;
Es stehen weitere Felder &#039;Repeats&#039; und &#039;Repeatdelay in sec&#039; zur Verfügung. Eine hier getätigte Einstellung bewirkt X-fache Wiederholung von gesetzten Befehlen im Abstand der gesetzten Sekunden.&lt;br /&gt;
&lt;br /&gt;
Weiterhin kann über das Auswahlfeld &#039;priotity&#039; bei jedem &#039;affectes device&#039; die Reihenfolge beim abarbeiten der Befehle beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequenz &amp;lt;Suchmuster&amp;gt; ===&lt;br /&gt;
In diesem Attribut können ein oder mehrere Suchmuster angegeben werden ,die eine Schaltsequenz darstellen und vom Device erkannt werden.&lt;br /&gt;
&lt;br /&gt;
Die Angabe muss folgende Syntax haben:&lt;br /&gt;
:&amp;lt;code&amp;gt;Device1:reading1:event1 Device1:reading1:event1-2 Device1:reading1:event1-3/..../....&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mehrere Suchmuster müssen durch &amp;quot;/&amp;quot; getrennt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
:&amp;lt;code&amp;gt;Dummy:state:on Dummy:state:off Dummy:state:on&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erkennt das Device dieses Suchmuster in den Schaltvorgängen des Devices (Dummy), wird das Reading &amp;quot;SEQUENCE&amp;quot; auf &amp;quot;match&amp;quot; gesetzt, das Reading &amp;quot;SEQUENCE_NUMBER&amp;quot; auf die Nummer der gefundenen Sequenz, wenn es mehrere Suchmuster gibt. Beide Readings können in den &amp;quot;Conditions&amp;quot; eines Schaltbefehles abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequence_time &amp;lt;Zeit in Sekunden&amp;gt; ===&lt;br /&gt;
Beinhaltet die Zeit in Sekunden, die es dauern darf, um eine Sequenz vollständig auszuführen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Extensions (0:1) ===&lt;br /&gt;
Es wird eine zusätzliche Schaltoption &#039;MSwitchToggle&#039; in den Geräten angeboten. Diese kann genutzt werden, wenn zuschaltende Geräte eine Togglefunktion nicht von Haus aus anbieten.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe muss in folgendem Format gemacht werden:&lt;br /&gt;
:&amp;lt;code&amp;gt;on/off/state/suchmuster1/suchmuster2&amp;lt;/code&amp;gt;, wobei die letzten drei Angaben optional sind.&lt;br /&gt;
&lt;br /&gt;
Funktion: Bei Ausführung des Befehls wird das Gerät &#039;on&#039; oder &#039;off&#039; geschaltet (on/off), Voraussetzung ist, dass der &#039;state&#039; dieses Gerätes auch den &#039;state on&#039; oder &#039;off&#039; annimmt. Sollte dieses nicht der Fall sein, so kann mit dem Feld &#039;state&#039; angegeben werden, in welchem Reading der aktuelle Status vorkommt und wie dieser lautet (suchmuster1/suchmuster2). Dieses &#039;state&#039; kann mehrere Angaben enthalten, das Vorkommen der Suchmuster ist aber Voraussetzung.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Delete_Delays (0:1) ===&lt;br /&gt;
Bewirkt das Löschen aller anstehende Timer (Delays) bei dem Auftreten eines erneuten, passenden Events. Bei der Option &#039;0&#039; bleiben bereits gesetzte Delays aus einem vorherigen, getriggertem Event erhalten und werden ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1)&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Devicecmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz liefern (bei Abfrage set DEVICE ?).&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Webcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut Webcmd hinterlegt haben. Die in Webcmd hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten.&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Activate_MSwitchcmds (0:1) ===&lt;br /&gt;
Fügt jedem vorhandenen Device as Attribut &#039;MSwitchcmd&#039; hinzu.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_MSwitchcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut MSwitchcmds hinterlegt haben. Die in MSwitchcmds hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten. Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr Angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Lock_Quickedit (0:1) ===&lt;br /&gt;
Voreinstellung für die Auswahlliste &#039;Affected Devices&#039;. Bei der Option (1) ist diese voreingestellt gesperrt und kann nur über einen zusätzlichen Button geändert werden. Da es sich hier um ein Feld mit der Möglichkeit einer Mehrfacheingabe handelt handelt ist die Voreinstellung 1, um versehentliche nicht gewünschte Änderungen zu vermeiden (Auswahl einer Option ohne &#039;Strg&#039; bewirkt das löschen aller bereits gesetzten Optionen).&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay (0:10:20:30:60) ===&lt;br /&gt;
Diese Einstellung beeinflusst den Start von MSwitch nach einem FHEM Start. MSwitch ignoriert für die angegebene Zeit in Sekunden alle eingehenden Events um u.a. Startverzögerungen zu vermeiden. Bei nicht gesetztem Attribut gilt hier eine Zeit von 30 Sekunden. Diese sollte auch nur in Ausnahmefällen bzw. bei besonderem Bedarf geändert werden.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (30).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Ignore_Types ===&lt;br /&gt;
Beinhaltet eine Liste von Device&#039;&#039;typen&#039;&#039;, die in den Auswahllisten &#039;&#039;nicht&#039;&#039; dargestellt werden. Hier ist es sinnvoll, Devicetypen einzutragen, die in aller Regel nicht geschaltet werden oder nicht geschaltet werden können, um die Auswahllisten übersichtlicher zu halten. Einzelne Devicetypen sind durch Leerzeichen zu trennen.&lt;br /&gt;
&lt;br /&gt;
Voreinstellung: notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe kann hier in 2 Arten getätigt werden:&lt;br /&gt;
# eine Liste von devicetypen.&lt;br /&gt;
# Angabe einer devspec z.B. &amp;quot;TYPE=watchdog&amp;quot;. Hier ist zu beachten, dass in diesem Fall alle Geräte in die Ignoreliste einbezogen werden, die NICHT der devspec entsprechen. Weiterhin muss die devspec in Anführungszeichen gesetzt werden!&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Trigger_Filter ===&lt;br /&gt;
Beinhaltet eine Liste von Events, die bei eingehenden Events unberücksichtigt bleiben. Diese werde dann auch nicht gespeichert.&lt;br /&gt;
&lt;br /&gt;
Hier kann mit Wildcards (*) gearbeitet werden. Einzelne Events sind durch Komma &#039;,&#039; zu trennen.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (keine).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Wait (sec)===&lt;br /&gt;
Bei gesetztem Attribut (Zeit in Sekunden) nimmt Das MSwitch Device für den eingestellten Zeitraum keine Befehle mehr entgegen und ignoriert eingehende Events&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Event_Id_Distributor ===&lt;br /&gt;
Dieses Attribut hat nur dann eine Funktion, wenn auch das Attribut &#039;MSwitchExpert&#039; auf &#039;1&#039; gesetzt ist.&lt;br /&gt;
Hier können verschiedene auslösende Events auf Aktionen mit angegebenen IDs umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Sollte bei den &#039;trigger details :&#039; in einem Zweig ( cmd1 ) z.B. auf mehrere Events getriggert werden ( regex z.B. state:(on|off) ) so werden für beide Events jeweils der Zweig &#039;cmd1&#039; - alle  Aktionen ohneID - ausgeführt. Durch entsprechende Einträge kann für entsprechende Events auf eine Aktion umgeleitet werden, für die eine ID definiert ist. Die Syntax lautet:&lt;br /&gt;
:&amp;lt;code&amp;gt;state:on=&amp;gt;cmd1 ID 1,2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden bei auslösendem Event &#039;state:on&#039; nur die Aktionen aus cmd1 mit den IDs 1 und 2 ausgeführt. Mehrere Angaben sind durch new Line zu trennen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Selftrigger_always (0,1)===&lt;br /&gt;
(dieses Attribut steht ab Modulversion 2.5 zur Verfügung)&lt;br /&gt;
&lt;br /&gt;
Die Aktivierung dieses Attributes (1) bewirkt, dass alle SET Aktionen des Devices einen (internen) Event auslösen, auf die das Device selber reagiert. Diese Option kann zusätzlich zu einem vorhandenen Trigger aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Diese Events sind lediglich Device intern, d.h es werden keine Modulübergreifenden Events ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Auftretende und auswertbare interne Events haben immer folgendes Format und können darüber ausgewertet werden.&lt;br /&gt;
&lt;br /&gt;
MSwitch_Self:aktion:wert &lt;br /&gt;
MSwitch_Self:pct:100&lt;br /&gt;
&lt;br /&gt;
Es werden nur interne Events für set-Aktionen ausgelöst, die im Attribut setlist hinterlegt sind.&lt;br /&gt;
&lt;br /&gt;
Als weitere Besonderheit unterliegen diese internen Events nicht dem &#039;wait&#039; Befehl/Attribut.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Mode (Notify,Full,Toggle,Dummy)===&lt;br /&gt;
Schaltet das Modul zwischen verschiedenen Modi um, mit entsprechend angepasster Weboberfläche.&lt;br /&gt;
&lt;br /&gt;
==== Notify ====&lt;br /&gt;
Das Device kann nicht manuell umgeschaltet werden, es gibt nur zwei ausführbare Zweige (execute &#039;cmd1&#039; commands und execute &#039;cmd2&#039; commands). Der Status des Devices wird nicht als &#039;on&#039; oder &#039;off&#039; angezeigt, sondern lediglich als &#039;active&#039;&lt;br /&gt;
&lt;br /&gt;
Dieser Mode ist am ehesten mit einem Notify zu Vergleichen.&lt;br /&gt;
==== Full ====&lt;br /&gt;
Es stehen alle Funktionen zur Verfügung.&lt;br /&gt;
==== Toggle ====&lt;br /&gt;
Sehr vereinfachter Mode. Es stehen keine verschiedenen Zweige zur Verfügung. Hier ist das Device manuell schaltbar und wird bei jedem definierten Event &#039;Umgeschaltet&#039;, entsprechend definierte Befehle für &#039;cmd1&#039; oder &#039;cmd2&#039; werden ausgeführt.&lt;br /&gt;
==== Dummy====&lt;br /&gt;
ACHTUNG: Funktionsänderung mit V2.61&lt;br /&gt;
&lt;br /&gt;
Der Mode &#039;Dummy&#039; ist ein eingeschränkter Modus. &lt;br /&gt;
Dieser bietet die Funktionalität eines Dummys kombiniert mit der Funktionalität eines Notifys und kann somit die gerne genutzte Kombination Dummy-Notify gegen ein Device ersetzen.&lt;br /&gt;
&lt;br /&gt;
Achtung: Devices die einmal in dem Modus &#039;Dummy&#039; gesetzt wurden können nicht wieder in einen anderen Mode geschaltet werden ! &lt;br /&gt;
&lt;br /&gt;
Der Dummy-Mode kann nur in einem neu angelegtem, leeren MSwitch aktiviert werden. Sobald ein angelegtes MSwitch einmal verändert wurde (modify trigger etc.) ist ein Umschalten nicht mehr möglich und die Option nicht mehr verfügbar.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Condition_Time (0,1)===&lt;br /&gt;
In der Grundeinstellung (0) werden für das zeitgesteuerte Schalten keine definierten Conditionen im Feld &#039;Trigger condition&#039; überprüft, sondern die Schaltbefehle werden in jedem Fall ausgeführt. Mit der Einstellung (1) wird diese Überprüfung auch für zeitgesteuerte Befehle zugeschaltet.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Time (HH:MM:SS-HH:MM:SS)===&lt;br /&gt;
Bei Aktivierung wird vor jedem Ausführen eines verzögerten Befehls ( Delay ) eine Zufallszeit generiert, die im Rahme der hier angegebenen Zeitspanne liegt. Auf diese Zufallszahl kann in den Delays zugegriffen werden, durch die Angabe &#039;[random]&#039; statt einer direkten Zeitangabe. Bei nicht gesetztem Attribut ergibt die Angabe von &#039; [random] &#039; hier immer &#039;00:00:00&#039;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Number ===&lt;br /&gt;
Bei Aktivierung dieses Attributes (der Inhalt kann einen beliebige Zahl sein) werden vom Device 2 Readings angelegt (Device:RandomNr) und (Device:RandomNr1). RandomNr wird vor jedem Ausführen eines Befehls aktualisiert und neu generiert, d.h wenn ein MSwitch Device mehrere Geräte schaltet, wird (auch in einem Durchgang) vor jedem Befehl dieses Reading neu gesetzt. RandomNr1 wird lediglich bei Ausführung des MSwitch Devices einmal neu gesetzt, d.h. nicht vor jedem Befehl der ausgeführt wird.&lt;br /&gt;
Die Readings werden mit einer Zufallszahl zwischen 0 und dem hier eingestellten Wert gesetzt.&lt;br /&gt;
&lt;br /&gt;
Auf diese Readings kann in jeder Condition mit z.B. &#039;[$NAME:ReadingNr1] = 1&#039; zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
D.h., das in der Condition angegebene Reading ( [$NAME:ReadingNr1] ) muss in diesem Fall den Wert 1 angenommen haben, ansonsten wird der Befehl nicht ausgeführt. &lt;br /&gt;
Der Befehl wird somit nur mit einer Wahrscheinlichkeit von 1 zu ( gesetzter Wert im Attr. ) ausgeführt.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Reset_EVT_CMD1(2)_COUNT ===&lt;br /&gt;
Bei Aktivierung dieses Attributes steht in den Readings das Reading &#039;EVT_CMD1_COUNT&#039; bzw. &#039;EVT_CMD2_COUNT&#039; zur Verfügung. Dieses kann in den Conditions genutzt werden, um z.B. nur bei jedem x-ten Eintreffen eines auslösenden Events einen Befehl auszuführen. Bei jedem Eintreffen eines gültigen Events werden die Zähler um 1 erhöht (für den jeweiligen Zweig). &lt;br /&gt;
Ist hier der Wert &#039;0&#039; eingetragen, wird der Zähler fortlaufend (endlos) erhöht. Wird ein Wert größer 0 eingetragen, wird der Zähler mit Erreichen dieses Wertes automatisch wieder auf Null gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit Löschen dieses Attributes werden die entsprechenden Readings ebenfalls gelöscht.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Safemode (0:1)===&lt;br /&gt;
Bietet einen (gewissen) Schutz vor falschen Konfigurationen und somit entstehenden Endlosschleifen.&lt;br /&gt;
Bei aktiviertem Attribut (1) erkennt das Modul Endlosschleifen eines Devices und beendet diese.&lt;br /&gt;
&lt;br /&gt;
In diesem Fall erfolgt ein Logeintrag und das Device wird per Attribut auf &#039;Disabled&#039; gesetzt.&lt;br /&gt;
Es wird ein letztes Event generiert, auf das reagiert werden kann:&lt;br /&gt;
:&amp;lt;code&amp;gt;2018-05-31 09:39:21 MSwitch &amp;lt;NAME&amp;gt; Safemode: on&amp;lt;/code&amp;gt;&lt;br /&gt;
Im Webinterface erfolgt bei betroffenem Device ein entsprechender Hinweis.&lt;br /&gt;
&lt;br /&gt;
In der Grundkonfiguration ist dieses Attribut nicht gesetzt, es empfiehlt sich aber, bei neuen (komplizierten) Devices, dieses - zumindest anfänglich - zu aktivieren.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Read_Log(0:1)===&lt;br /&gt;
Ermöglicht den Zugriff auf das Logfile als Trigger.&lt;br /&gt;
&lt;br /&gt;
Hier gibt es mehrere Konfigurationsmöglichkeiten:&lt;br /&gt;
* Bei aktiviertem Attribut enthält die Auswahl des Triggerdevices die Option &#039;LOGFILE&#039;. Bei dieser Auswahl werde alle Logeinträge erkannt und in ein internes Event umgewandelt, auf das regiert werden kann.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl &#039;GLOBAL&#039; im &#039;Trigger_Device&#039; wird auf ALLE Events und alle Logeinträge reagiert.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl eines bestimmten Devices im &#039;Trigger_Device&#039; wird auf alle Events  und auf alle Logeinträge des gewählten Devices reagiert. Hier ist zu beachten, dass FHEM mir keine Möglichkeit bietet, wirklich herauszufinden, welches Device denn nun einen Logeintrag generiert hat. D.h., dieses wird vom Vorhandensein des Namens im Logeintrag abhängig gemacht und MSwitch reagiert nur dann auf einen Logeintrag, wenn der Name des Devices in diesem Eintrag vorhanden ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Help(0:1)===&lt;br /&gt;
Schaltet Hilfebuttons zu den einzelnen Eingabefeldern an oder aus.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Comments(0:1)===&lt;br /&gt;
Schaltet Kommentarfelder zu den einzelnen &#039;affected_devices an.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_generate_Events(0:1)===&lt;br /&gt;
Reduziert bei Einstellung &#039;1&#039; die vom MSwitch-Devices erzeugten Events auf ein absolutes Minimum. Insbesondere bei Verwendung von &#039;MSwitch_Read_Log&#039; zu empfehlen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay ===&lt;br /&gt;
Bestimmt die Verzögerungszeit des MSwitches nach FHEM-Start in Sekunden. In diesem Zeitraum reagiert das ??Event??(Red: ist hier &amp;quot;Device&amp;quot; gemeint?) nicht auf Events. Die Vorgabe ist hier zehn Sekunden. Diese wird auch dann angenommen, wenn das Attribut nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Inforoom ===&lt;br /&gt;
Mit diesem Attribut wird die Raumansicht eines mit dem Attribut bestimmten Raumes verändert. Dadurch sollen die wichtigsten Informationen aller MSwitch-Devices auf eine Seite dargestellt werden. Zur Nutzung sollten alle MSwitch-Devices (zusätzlich) in einen Raum sortiert werden und dieser Raum im Attribut eingestellt werden.&lt;br /&gt;
&lt;br /&gt;
Wichtig: Eine Änderung dieses Attributes bewirkt immer eine Änderung dieses Attributes in &#039;&#039;allen&#039;&#039; MSwitch devices: Es muss nur in einem Device gesetzt oder gelöscht werden um alle Devices zu erfassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
MSwitch_Screen_1.png|Raumansicht des Raumes MSwitch mit gesetztem Attribut &#039;MSwitch&#039;&lt;br /&gt;
MSwitch_Screen_2.png|Raumansicht des Raumes MSwitch ohne gesetztes Attribut&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es werden folgende Informationen bereitgestellt:&lt;br /&gt;
* Infobutton zeigt den im Device gespeicherten Textes des Attributes &#039;comment&#039;&lt;br /&gt;
* Device und Events, die das Device triggern&lt;br /&gt;
* Zeiten, zu denen verschiedene Zweige des Devices ausgeführt werden&lt;br /&gt;
* Devices, die durch das MSwitch Device geschaltet werden&lt;br /&gt;
* State des Devices&lt;br /&gt;
&lt;br /&gt;
== Integrierte Funktionen ==&lt;br /&gt;
&lt;br /&gt;
=== Average ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
=== Tendency ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[TEND&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;Mindestwert&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[TEND2:countdown] &amp;gt; 2&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Es wird jeweils der Durchschnitt von 2 Wertepaaren gebildet. In diesem Fall werden die letzten 4 Werte herangezogen.&amp;lt;br&amp;gt;&lt;br /&gt;
Paar 1 = Aktueller und letzter Wert, Paar 2 = Die 2 vorherigen Werte.&amp;lt;br&amp;gt;&lt;br /&gt;
Bei TEND3 werden die letzten 6 Werte zur Paarbildung genutzt.&lt;br /&gt;
&lt;br /&gt;
Mindestwert:&lt;br /&gt;
Der Wertunterschied zwischen den Wertepaaren, der minimal erreicht sein muss, um eine Tendenz zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Rechenzeichen (&amp;gt;&amp;lt;):&lt;br /&gt;
Dieses ist hier nicht als Rechenzeichen zu werten, sonder als Tendenz-Anzeige. ( &amp;lt; es wird nach fallender Tendenz gesucht / &amp;gt; sucht nach steigender Tendenz).&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolgt einmalig bei Erkennung der gesuchten Tendenz.&lt;br /&gt;
Danach erfolgt keine Schaltung mehr, solange bis eine Tendenz-Umkehr erfolgt ist.&lt;br /&gt;
Erst dann erfolgt wieder eine Schaltung bei erneuter Tendenz-Umkehr in gesuchte Richtung.&lt;br /&gt;
&lt;br /&gt;
=== Difference ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[DIFF&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;differenz&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[DIFF2:countdown] &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Gespeicherter Wert (in diesem Fall der vorletzte).&lt;br /&gt;
&lt;br /&gt;
Differenz:&lt;br /&gt;
Geforderter Differenz zwischen aktuellem und vorletztem Wert.&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolg wenn diese Bedingung &#039;wahr&#039; ist.&lt;br /&gt;
&lt;br /&gt;
Folgende Readings werden zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
DIFFERENCE (true/false) - Schaltbedingung erkannt ja/nein&lt;br /&gt;
&lt;br /&gt;
DIFFDIRECTION (up/down) - Richtung der erkannten Bedingung (steigend/fallend)&lt;br /&gt;
&lt;br /&gt;
=== Increase ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
== Tipps, Tricks, Kurzbeispiele ==&lt;br /&gt;
Wird stetig ergänzt .&lt;br /&gt;
&lt;br /&gt;
=== Blinken - Falls nicht im Device vorhanden ===&lt;br /&gt;
[[Datei:MSwitch MSwitchblink.png|center|704px]]&lt;br /&gt;
&amp;lt;br clear=all&amp;gt;&lt;br /&gt;
Lässt ein beliebiges Device 5 mal togglen, mit einem Intervall von 0.5 Sekunden (Blinkzeit somit 2,5 Sekunden)&amp;lt;br&amp;gt;&lt;br /&gt;
Die MSwitchtoggle-Funktion muss per ATTR aktiviert werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Die Repeatfunktion ist nur im Expertmode verfügbar, auch per ATTR einstellbar.&lt;br /&gt;
&lt;br /&gt;
=== Linearschalter ===&lt;br /&gt;
Umsetzung eines Linearschalters mit MSwitch.&lt;br /&gt;
&lt;br /&gt;
Eingang: Beliebiges Reading als numerischer Wert.&lt;br /&gt;
&lt;br /&gt;
Ausgang: Wird entsprechend Linear / oder umgekehrt Linear zum Eingang geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgend die Rawdefinition des MSwitchdevices und zweier Dummys (selbsterklärend)&lt;br /&gt;
&lt;br /&gt;
Alle Devices werden im Raum Lineartest angelegt, die Dummy müssen zuerst angelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod linearausgang dummy&lt;br /&gt;
attr linearausgang room Lineartest&lt;br /&gt;
attr linearausgang setList state:slider,0,1,100&lt;br /&gt;
attr linearausgang webCmd state&lt;br /&gt;
setstate linearausgang state 57&lt;br /&gt;
setstate linearausgang 2018-06-06 18:06:12 state state 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod lineareingang dummy&lt;br /&gt;
attr lineareingang room Lineartest&lt;br /&gt;
attr lineareingang setList state:slider,0,1,15000&lt;br /&gt;
attr lineareingang webCmd state&lt;br /&gt;
setstate lineareingang 6422&lt;br /&gt;
setstate lineareingang 2018-06-06 18:06:12 state 6422&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod Linearschalter MSwitch lineareingang  # linearausgang FreeCmd&lt;br /&gt;
attr Linearschalter MSwitch_Debug 0&lt;br /&gt;
attr Linearschalter MSwitch_Delete_Delays 1&lt;br /&gt;
attr Linearschalter MSwitch_Expert 0&lt;br /&gt;
attr Linearschalter MSwitch_Extensions 0&lt;br /&gt;
attr Linearschalter MSwitch_Help 0&lt;br /&gt;
attr Linearschalter MSwitch_Ignore_Types notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
attr Linearschalter MSwitch_Include_Devicecmds 1&lt;br /&gt;
attr Linearschalter MSwitch_Include_MSwitchcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Include_Webcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Inforoom MSwitch&lt;br /&gt;
attr Linearschalter MSwitch_Lock_Quickedit 1&lt;br /&gt;
attr Linearschalter MSwitch_Mode Notify&lt;br /&gt;
attr Linearschalter room Lineartest&lt;br /&gt;
&lt;br /&gt;
setstate Linearschalter active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:03:50 .Device_Affected FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:04:35 .Device_Affected_Details FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 );;my $emin=0;;my $emax=15000;;my $amin=100;;my $amax=0;;$eingang = $emin if $eingang &amp;lt; $emin;;$eingang = $emax if $eingang &amp;gt; $emax;;my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin;;readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 );;},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter:to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 .Device_Events no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .First_init done&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_on *&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_condition &lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_on no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_time &lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .V_Check V 0.3&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVENT state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTFULL lineareingang:state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART1 lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART2 state&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART3  6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 Exec_cmd set linearausgang state [Linearschalter:to_set]&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 Trigger_device lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 Trigger_log off&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 last_event state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:39:56 state active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 to_set 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
MSwitch -Configfile (bei Bedarf)&lt;br /&gt;
&amp;lt;pre&amp;gt;#V V1.54&lt;br /&gt;
#S .Device_Affected -&amp;gt; FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
#S .Device_Affected_Details -&amp;gt; FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 )[S]my $emin=0[S]my $emax=15000[S]my $amin=100[S]my $amax=0[S]$eingang = $emin if $eingang &amp;lt; $emin[S]$eingang = $emax if $eingang &amp;gt; $emax[S]my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin[S]readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 )[S]},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter.to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
#S .Device_Events -&amp;gt; no_trigger&lt;br /&gt;
#S .First_init -&amp;gt; done&lt;br /&gt;
#S .Trigger_Whitelist -&amp;gt; undef&lt;br /&gt;
#S .Trigger_cmd_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_cmd_on -&amp;gt; *&lt;br /&gt;
#S .Trigger_condition -&amp;gt; &lt;br /&gt;
#S .Trigger_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_on -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_time -&amp;gt; &lt;br /&gt;
#S .V_Check -&amp;gt; V 0.3&lt;br /&gt;
#S Trigger_device -&amp;gt; lineareingang&lt;br /&gt;
#S Trigger_log -&amp;gt; off&lt;br /&gt;
#S last_event -&amp;gt; state: 6422&lt;br /&gt;
#S state -&amp;gt; active&lt;br /&gt;
#A MSwitch_Ignore_Types -&amp;gt; notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
#A MSwitch_Include_MSwitchcmds -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Debug -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Help -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Devicecmds -&amp;gt; 1&lt;br /&gt;
#A MSwitch_Extensions -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Webcmds -&amp;gt; 0&lt;br /&gt;
#A room -&amp;gt; Lineartest&lt;br /&gt;
#A MSwitch_Inforoom -&amp;gt; MSwitch&lt;br /&gt;
#A MSwitch_Expert -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Lock_Quickedit -&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Thread über das Modul im {{Link2Forum|Topic=86199|LinkText=FHEM Forum}}&lt;br /&gt;
* {{Link2Forum|Topic=100119|Message=936495|LinkText=Gäste-WLAN der Fritzbox auswerten und Login per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=86199|Message=930133|LinkText=Schalten von vier Kanälen mit einem MSwitch-Device}}&lt;br /&gt;
* {{Link2Forum|Topic=99219|Message=926652|LinkText=Batterie-Überwachung. 1xTäglich per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=101091|Message=945389|LinkText=Licht (Alarm) in einem bestimmten Zeitraum schalten}}&lt;br /&gt;
* {{Link2Forum|Topic=100949|Message=944284|LinkText=Über Dummy-Schalter ein Timer (EIN/AUS) aktivieren}}&lt;br /&gt;
* {{Link2Forum|Topic=103083|Message=967710|LinkText=Ladezeit von Akku ermitteln u. Steckdose entsprechend schalten}}&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31476</id>
		<title>MSwitch</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31476"/>
		<updated>2019-11-01T20:00:06Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* MSwitch_Selftrigger_always (0,1) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[MSwitch]] ist ein Hilfsmodul, welches das Event- und/oder zeitgesteuerte Schalten von mehreren Devices oder das Ausführen von benutzerdefinierten Befehlssequenzen erlaubt.&lt;br /&gt;
&lt;br /&gt;
Die Stärke bzw. das Unterscheidungsmerkmal dieses Moduls liegt in der Konfigurierbarkeit über ein Webinterface. Diese Konfiguration kann jederzeit geändert oder erweitert werden. &lt;br /&gt;
&lt;br /&gt;
Byte09: &#039;&#039;Die Grundidee zu MSwitch kam mir, weil ich bei der Arbeit mit FHEM für meinen Geschmack zu viele Module für die verschiedenen Aufgaben brauchte - zu allem Überfluss alle mit unterschiedlicher Syntax. Zwar ist DOIF hiervon ausgenommen (da hiermit wohl auch fast jede Aufgabe lösbar ist), aber ich konnte mich leider nicht daran gewöhnen und somit wurde jedes DOIF für mich zu einem echten Projekt. Was ich wollte war ein Modul, mit dem ich alles erledigen kann. Daher entschloss ich mich schon nach fast einem knappen Jahr FHEM-Nutzung mein eigenes Modul zu schreiben, welches diese Anforderung erfüllt. MSwitch beinhaltet die Funktionalität aller bisherigen Hilfsmodule wie z.B. Notify, Doif, Watchdog, Dummy,( ab Modulversion 2.2 auch Sequenz ) es lassen sich all deren Funktionen umsetzen.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;MSwitch wird permanent - vorrangig nach meinen Bedürfnissen - weiterentwickelt, gerne nehme ich aber auch Anregungen von anderen Nutzern auf.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=MSwitch&lt;br /&gt;
|ModType=h&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=98_MSwitch.pm&lt;br /&gt;
|ModOwner=Byte09}}&lt;br /&gt;
&lt;br /&gt;
== Grundsätzliche Überlegungen ==&lt;br /&gt;
Um das Modul zu nutzen, muss man zuerst folgende Fragen beantworten:&lt;br /&gt;
&lt;br /&gt;
* Welches Gerät soll auslösen oder zu welcher Zeit soll eine Auslösung erfolgen.&lt;br /&gt;
: Dies ist der Trigger. Jedes Event aus dem Eventmonitor kann als Trigger dienen. Will man mehrere Geräte als gleichzeitige Auslöser betreiben, so muss das Device GLOBAL gewählt und die entsprechenden Geräte angegeben werden (dies erzeugt höhere Systemlast und ist nur im Expert-Modus verfügbar). Weiterhin kann auch zu fest definierten Zeiten, Zufallszeiten oder Intervallen, unabhängig von einem Trigger, geschaltet werden; auch eine Kombination beider Varianten ist möglich. Diese Einstellungen erfolgen im ersten Teil des Webinterfaces.&lt;br /&gt;
&lt;br /&gt;
* Welche Bedingungen sollen bei Auslösung erfüllt sein?&lt;br /&gt;
: Wenn diese Bedingungen erfüllt sind, werden Kommandos ausgelöst. Die Bedingungen werden im zweiten Teil des Webinterfaces eingegeben. Dabei unterscheidet das Modul zwischen zwei Kommando-Kanälen (cmd1 und cmd2) und den dazugehörigen Geräten.&lt;br /&gt;
&lt;br /&gt;
* Welche Kommandos sollen ausgelöst werden?&lt;br /&gt;
: Im dritten Teil des Webinterfaces werden dann die konkreten Kommandos eingegeben. Typischerweise wählt man dabei aus einer Liste der Kommandos aus, die die zugehörigen Geräte insgesamt aufweisen (also so, wie man auf den Geräteseiten selber Kommandos auswählt). Es gibt zudem ein so genanntes FreeCmd, das ein Geräteunabhängiges Kommando zulässt, beispielsweise reinen Perl-Code.&lt;br /&gt;
&lt;br /&gt;
* Welche weiteren Bedingungen sollen noch gelten?&lt;br /&gt;
: Hier sind Ereignisgesteuerte wie auch Zeitgesteuerte Bedingungen möglich. Diese Bedingungen werden auch in dem dritten Teil des Webinterfaces eingetragen. So sind Verzögerungen und Wiederholungen und weitere Bedingungen möglich.&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen, Installation und Grundbefehle ==&lt;br /&gt;
Das MSwitch-Modul ist ohne weitere Voraussetzungen nutzbar und wird derzeit in der Version 2.08 über FHEM Update verteilt. &lt;br /&gt;
&lt;br /&gt;
=== Definition und Einrichtung ===&lt;br /&gt;
Mit Hilfe von MSwitch kann man mehrere Devices gleichzeitig schalten. Diese Schaltungen befinden sich in zwei möglichen Zweigen bei MSwitch. Dabei unterscheidet man im Modul zwischen den beiden Kommandos cmd1 und cmd2. Die zu einem Kommando gehörenden Geräte werden wir auch Zweig nennen. Die einzelnen Devices jedes Zweiges können mit weiteren Schaltbedingungen versehen werden (zeit- oder ereignisgesteuert). &lt;br /&gt;
&lt;br /&gt;
Folgende Möglichkeiten zum definieren des MSwitch Devices stehen zur Verfügung:&lt;br /&gt;
:&amp;lt;code&amp;gt;define &amp;lt;name&amp;gt; MSwitch&amp;lt;/code&amp;gt;&lt;br /&gt;
Es wird ein leeres Device angelegt, das dann komplett über das Webinterface konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das define eines MSwitch Devices generiert lediglich eine &#039;leere Hülle&#039;. Alle relevante Einstellungen werden in Readings und/oder Hashes gespeichert. Daher stehen relevanten Daten &#039;&#039;nicht&#039;&#039; in der fhem.cfg! Vielmehr finden sich diese Daten in der Datei fhem.save (die Speicherung erfolgt durch den Befehl Fhemsave).&lt;br /&gt;
&lt;br /&gt;
=== set-Befehle ===&lt;br /&gt;
Es sind derzeit die folgenden set-Befehle implementiert.&lt;br /&gt;
&lt;br /&gt;
==== set active ====&lt;br /&gt;
Setzt das Device in den Status &#039;active&#039;.&lt;br /&gt;
&lt;br /&gt;
==== set inactive ====&lt;br /&gt;
Setzt das Device in den Status &#039;inactive&#039;, es werden keine Befehle mehr ausgeführt. Dieser Status entspricht dem Attribut &#039;disable&#039;, ist aber nicht mit dem roten Fragezeichen (fhem save) verbunden.&lt;br /&gt;
&lt;br /&gt;
==== set on/off [&amp;lt;parameter&amp;gt;]====&lt;br /&gt;
Setzt das Device in den Status &#039;on&#039; oder &#039;off&#039;. Alle Befehle der &#039;on/off-Zweige&#039; werden ausgeführt.&lt;br /&gt;
Optional kann den Befehlen &#039;on&#039; und &#039;off&#039; ein weiterer Parameter mit übergeben werden. Dieser wird im Reading &#039;Parameter&#039; hinterlegt und es kann sofort in &#039;Freecmds&#039; oder &#039;Conditions&#039; darauf zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
==== set reload_timer ====&lt;br /&gt;
Alle gesetzten Timer werden gelöscht und neu berechnet.&lt;br /&gt;
&lt;br /&gt;
==== set change_renamed &amp;lt;oldname&amp;gt; &amp;lt;newname&amp;gt; ====&lt;br /&gt;
Sollten sich Devicenammen im ausführenden Teil geändert habe (affected Devices, Conditions, etc.) so kann das MSwitch mit diesem Befehl angepasst werden, ohne alle Einstellungen neu einstellen zu müssen.&lt;br /&gt;
&lt;br /&gt;
==== set exec_cmd1 / set exec_cmd1 ID [&amp;lt;ID&amp;gt;] ====&lt;br /&gt;
Bewirkt das sofortige Ausführen des entsprechenden Befehlszweiges. Bei Angabe einer ID werden nur die Befehle mit der entsprechenden ID ausgeführt.&lt;br /&gt;
&lt;br /&gt;
==== set MSwitch_backup ====&lt;br /&gt;
Erstellt eine Backup-Datei aller MSwitch Devices unter ./fhem/MSwitch_backup.cfg.&lt;br /&gt;
&lt;br /&gt;
Daten dieser Datei können im Bedarfsfall für einzelne oder gleichzeitig alle MSwitch Devices wieder zurückgespielt (hergestellt) werden.&lt;br /&gt;
&lt;br /&gt;
==== set del_delays ====&lt;br /&gt;
Löscht alle anstehenden, verzögerten Befehle (delays).&lt;br /&gt;
&lt;br /&gt;
==== set reset_cmd_count:1,2 ====&lt;br /&gt;
Löscht das entsprechende EVT_CMD_COUNT - Reading (entspricht Rückstellung auf &#039;0&#039;).&lt;br /&gt;
&lt;br /&gt;
==== set fakeevent [&amp;lt;device&amp;gt;]:&amp;lt;reading&amp;gt;:&amp;lt;arg&amp;gt; ====&lt;br /&gt;
Beispiel: &amp;lt;device&amp;gt; fakeevent state:on&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ob der Name (&amp;lt;device&amp;gt;) angegeben werden muss, oder nicht, ist abhängig davon, ob auf ein einzelnes Device, oder GLOBAL getriggert wird. Bei GLOBALEN Triggern muss das Device mit angegeben werden. Wird auf ein Device getriggert, so wird das Device automatisch gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit diesem Befehl kann das MSwitch Device neu getriggert werden, indem hier ein Event &#039;gefaked&#039; wird. Das MSwitch Device reagiert dann so, als wäre dieses Event vom getriggerten Gerät generiert worden. &lt;br /&gt;
&lt;br /&gt;
Dieses kann nötig sein, um z.B. einen Watchdog zu realisieren, in dem es nötig ist, dass sich das MSwitch Device mit einem bestimmten Event selber neu triggert - ggf. mit einem entsprechenden Delay (affected Device muss dafür u.A. des MSwitch Device selber sein).&lt;br /&gt;
&lt;br /&gt;
Es wird hierbei KEIN echtes Event generiert welches das System beeinflusst, sondern ausschließlich ein MSwitch-Interner Befehl umgesetzt!&lt;br /&gt;
&lt;br /&gt;
Bei dem Einsatz dieser Möglichkeit sollte das Attribut &#039;MSwitch_Safemode&#039; UNBEDINGT aktiviert sein, da &#039;Experimente&#039; hier schnell in einer Endlosschleife enden können, die nur durch ein Reboot unterbrochen werden kann. &lt;br /&gt;
&lt;br /&gt;
Ggf. werde ich hier sogar eine entsprechende Änderung vornehmen, dass dieser Befehl nur zur Verfügung steht, wenn Safemode aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
=== get-Befehle ===&lt;br /&gt;
==== get show_timer [&amp;lt;show&amp;gt;&amp;lt;delete&amp;gt;] ====&lt;br /&gt;
;Show&lt;br /&gt;
:Zeigt alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren.&lt;br /&gt;
;Delete&lt;br /&gt;
:Löscht alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren. Schaltbefehle basierend auf rein zeitabhängigen Angaben werden neu berechnet und gesetzt.&lt;br /&gt;
&lt;br /&gt;
==== get restore_MSwitch_data [&amp;lt;this_device&amp;gt;&amp;lt;all_devices&amp;gt;] ====&lt;br /&gt;
;this_device&lt;br /&gt;
:Stellt die Daten des Devices aus der Backupdatei wieder her, sofern diese in der Backupdatei gefunden werden (gesucht wird hier nach dem Namen des Devices).&lt;br /&gt;
;all_devices&lt;br /&gt;
:Stellt die Daten aller MSwitch Devices wieder her, sofern diese in der Backupdatei vorhanden sind. Diese Aktion kann einige Zeit in Anspruch nehmen und wird daher im Hintergrund (nonblocking) ausgeführt. Nach Beendigung erfolgt eine Benachrichtigung.&lt;br /&gt;
&lt;br /&gt;
Die Devices sind nach einem Restore funktionsfähig. Empfohlen wird ein Neustart von FHEM.&lt;br /&gt;
&lt;br /&gt;
==== get_config ==== &lt;br /&gt;
Zeigt die Konfigurationsdatei des MSwitchdevices an; diese kann in dem Fenster editiert werden. Das sollte nur von erfahrenen Usern getan werden! Im Normalfall sollte das Device nur über die Weboberfläche konfiguriert werden und eine falsche Konfiguration kann hier zu einem FHEM Absturz führen.&lt;br /&gt;
&lt;br /&gt;
==== get_support_info ==== &lt;br /&gt;
Öffnet ein Fenster mit einer formatierten Ansicht aller Einstellungen des Devices. Bei Supportanfragen sollte dieses immer mit geposted werden.&lt;br /&gt;
&lt;br /&gt;
==== get_MSwitch_preconf ====&lt;br /&gt;
Lädt vorkonfigurierte MSwitch-Devices. Diese Option ist nur dann vorhanden, wenn das Aktualisieren dieser vorkonfigurierten Devices im FHEM Update aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
Diese kann durch ein einmaliges Update erfolgen mit:&lt;br /&gt;
:&amp;lt;code&amp;gt;update all https://raw.githubusercontent.com/Byte009/MSwitch_Addons/master/controls_mswitchaddons.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Webinterface ==&lt;br /&gt;
MSwitch wird im Wesentlichen über das Webinterface eingerichtet. Wählt man das folgende Attribut&lt;br /&gt;
:&amp;lt;code&amp;gt;attr &amp;lt;name&amp;gt; MSwitch_Help 1&amp;lt;/code&amp;gt;&lt;br /&gt;
so wird im Modul selber eine sehr umfangreiche Hilfe angezeigt. Über das gesamte Webinterface hinweg erscheinen kleine Fragezeichen, die man anklicken kann und die beschreiben, was in dem jeweiligen Textfeld sinnvollerweise einzugeben ist bzw. was das Modul an dieser Stelle erwartet.&lt;br /&gt;
&lt;br /&gt;
Das Webinterface besteht aus vier Teilen. Änderungen in jedem Abschnitt müssen in dem jeweiligen Teil bestätigt werden und auch nur diese werden gespeichert. Bevor ein weiterer Teil bearbeitet wird, sollten Änderungen gespeichert werden, sie gehen sonst verloren.&lt;br /&gt;
&lt;br /&gt;
=== Trigger device/time ===&lt;br /&gt;
==== Trigger Device ====&lt;br /&gt;
In diesem Feld wird das Device ausgewählt, dessen Events eine Aktion auslösen sollen. Dazu werden alle verfügbaren Devices in einem Dropdownfeld angeboten.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es eine Auswahl &#039;GLOBAL&#039;, wenn das Attribut &#039;MSwitch_Expert&#039; gesetzt ist. Bei Auswahl dieser Option werden &#039;&#039;&#039;alle&#039;&#039;&#039; von FHEM generierten Events durch das MSwitch Device weiterverarbeitet, eine weitere Begrenzung der aktivierenden Events kann (und sollte) dann in einem folgenden Eingabefeld erfolgen, um die Systemlast zu reduzieren.&lt;br /&gt;
&lt;br /&gt;
==== Trigger Device Global Whitelist ====&lt;br /&gt;
Dieses Feld ist nur verfügbar, wenn als Trigger &#039;GLOBAL&#039; gewählt wurde.&lt;br /&gt;
&lt;br /&gt;
Hier kann die Liste eingehender Events weiter eingeschränkt werden. Es handelt sich um eine Whitelist, d.h., wenn es keine Einträge gibt, werden Events aller Devices verarbeitet. Sobald ein oder mehrere Einträge gemacht werden, werden nur noch Events der hier benannten Devices verarbeitet. Als Angabe können hier Devices benannt werden oder ganze DeviceTypen (z.B. TYPE=FS20). Mehrere Angaben sind durch Komma zu trennen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:MSwitchWebinterface1.png|400px|thumb|right|Webinterface, oben]]&lt;br /&gt;
Im gezeigten Beispiel wurde GLOBAL gewählt, weil nicht ein einzelnes Device, sondern eine Kombination aus zwei Geräten auslösen soll. Es werden also alle Ereignisse betrachtet, wobei die Whitelist dann auf die Devices Schlafzimmer (ein Temperaturmessgerät) und Schlafzimmerfenster (ein [[HM-Sec-SCo Tür-Fensterkontakt, optisch|optischer Kontakt]]) einschränkt. &lt;br /&gt;
&lt;br /&gt;
==== Trigger time ==== &lt;br /&gt;
Es besteht die Möglichkeit, das Modul (neben den Events) zu festen Zeiten auszulösen. Dann wären in die leer stehenden Zeilen bei &amp;quot;at&amp;quot; entsprechende Termine einzutragen. Zeitangaben erfolgen durch [STUNDEN:MINUTEN|TAGE], wobei die Tage von 1-7 gezählt werden (1 steht für Montag, 7 für Sonntag usw.). &lt;br /&gt;
Mehrere Zeitvorgaben können direkt aneinandergereiht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [17:00|1][18:30|23] den Trigger montags um 17 Uhr auslösen und dienstags sowie mittwochs um 18:30 Uhr.&lt;br /&gt;
Bei [00:10*20:00-21:00] würde der Schaltbefehl von 21 Uhr bis 21 Uhr alle 10 Minuten ausgeführt. Bei [?20:00-21:00] würde der Schaltbefehl zu einem zufälligen Zeitpunkt zwischen 20 und 21 Uhr ausgeführt.  [20:00|$we] bedeutet, dass nur am Wochenende um 20:00 geschaltet wird.&lt;br /&gt;
&lt;br /&gt;
==== Trigger conditions ====&lt;br /&gt;
Hier kann die Angabe von Bedingungen erfolgen, die zusätzlich zu dem triggernden Device erfüllt sein müssen.&lt;br /&gt;
Diese Bedingungen sind eng an DOIF-Syntax angelehnt. Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich.&lt;br /&gt;
&lt;br /&gt;
Wird in diesem Feld keine Angabe gemacht, so erfolgt der Schaltvorgang nur durch das triggernde Device ohne weitere Bedingungen.&lt;br /&gt;
&lt;br /&gt;
;Zeitabhängigkeit&lt;br /&gt;
:[19:10-23:00] - Trigger des Devices erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
;Readingabhängige Trigger&lt;br /&gt;
:[Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Trigger des Device erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
:Werden Readings mit Strings abgefragt (on,off,etc.), ist statt des Gleichheitszeichens &amp;quot;=&amp;quot; der Operator &amp;quot;eq&amp;quot; zu nutzen, der String muss in Anführungszeichen &amp;quot;&amp;quot; gesetzt werden.&lt;br /&gt;
;mehrere Beispiele&lt;br /&gt;
:[19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
:[19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
:[10:00-11:00|13] - schaltet Montag und Mittwoch zwischen 10 Uhr und 11 Uhr.&lt;br /&gt;
:[{ sunset() }-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
:{ !$we } löst den Schaltvorgang nur Werktagen an aus.&lt;br /&gt;
:{ $we } löst den Schaltvorgang nur an Wochenenden, Feiertagen aus.&lt;br /&gt;
&lt;br /&gt;
Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (beispielsweise würde dann am Mittwoch noch der Schaltvorgang erfolgen, obwohl als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
Bedingungen in diesem Feld gelten nur für auslösende Trigger eines Devices und haben keinen Einfluss auf zeitgesteuerte Auslöser.&lt;br /&gt;
&lt;br /&gt;
=== Trigger details ===&lt;br /&gt;
[[Datei:MSwitchWebinterface2.png|600px|thumb|right|Webinterface, Mitte]]&lt;br /&gt;
Während im obigen Feld das Device ausgewählt  werden konnte, wird hier das Ereignis festgelegt. Das Eingabefeld besteht aus mehreren Einzelfeldern.&lt;br /&gt;
&lt;br /&gt;
Im abgebildeten Fall wird cmd1 ausgelöst, wenn der Zustand des Schlafzimmerfenster-Sensors meldet, dass das Fenster offen ist. Cmd2 wird ausgelöst, wenn die Temperatur des Schlafzimmersensors unter einen bestimmten Wert fallen wird.&lt;br /&gt;
&lt;br /&gt;
==== execute &#039;cmd1/cmd2&#039;  ====&lt;br /&gt;
Hier kann  aus einer vorbelegten Dropdownliste ausgewählt werden, welches ankommende Event den entsprechenden Befehlszweig auslösen soll. In dieser Liste werden bei entsprechender Einstellung alle ankommenden Events eines vorher definierten Devices gespeichert. In einem weiteren Feld (siehe unten) können Events manuell zugefügt werden.&lt;br /&gt;
&lt;br /&gt;
==== Save incomming events ====&lt;br /&gt;
Bei Aktivierung dieser Option werden alle ankommenden Events des oben definierten Devices (oder Global) gespeichert und in entsprechenden Dropdownlisten angeboten.&lt;br /&gt;
&lt;br /&gt;
Da hier doch erhebliche Datenmengen anfallen können (je nach Device) wird empfohlen, diese Option nach der Konfiguration des Devices zu deaktivieren.&lt;br /&gt;
&lt;br /&gt;
==== add event ====&lt;br /&gt;
Hier besteht die Möglichkeit, unabhängig von der Option, ankommende Events automatisch zu speichern. Manuell Events anzulegen, die in den Dropdownliste zur Auswahl angeboten werden, ohne das entsprechendes Event erst vom Device geliefert werden muss.&lt;br /&gt;
&lt;br /&gt;
Es können mehrere Events gleichzeitig eingegeben werden, eine Trennung erfolgt durch &amp;quot; , &amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Hier ist zu unterscheiden, ob das gewählte triggernde Device ein einfaches Device ist oder ob der Trigger &#039;GLOBAL&#039; ist.&lt;br /&gt;
Bei triggernden Devices können Events in folgendem Formaten zugefügt werden:&lt;br /&gt;
&lt;br /&gt;
- *                                                    - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:wert   (z.b. state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:*      (z.b. state:* )                       - Aktion erfolgt auf die Events &amp;quot;state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:(wert1/wert2/wert3) (z.b. state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;state:left&amp;quot; oder &amp;quot;state:right&amp;quot; etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Falls auf &#039;GLOBALE&#039; Events getriggert wird, muss das auslösende Device vorangestellt werden:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
- *                                                           - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:wert   (z.b. device:state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;device:state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:*      (z.b. device:state:* )                       - Aktion erfolgt auf die Events &amp;quot;device:state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:(wert1/wert2/wert3) (z.b. device:state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;device:state:left&amp;quot; oder &amp;quot;devicestate:right&amp;quot; etc.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Device kann auch hier gegen &amp;quot;*&amp;quot; ersetzt werden (*:state:on). In diesem Fall erfolgt eine Aktion auf alle Events die z.B. &amp;quot;state:on&amp;quot; enthalten, egal welches Device triggert.&lt;br /&gt;
&lt;br /&gt;
==== test event ====&lt;br /&gt;
Dieses Feld wird angeboten, wenn entsprechende vom Triggerdevice gelieferte Events gespeichert wurden.&lt;br /&gt;
&lt;br /&gt;
Durch Auslösen dieser Funktion wird das Event simuliert und entsprechende definierte Aktionen ausgelöst. Diese Funktion dient ausschließlich zum Testen der eingestellten Konfiguration. Alle entsprechenden Befehle werden ausgeführt, als würde das Event real eintreffen.&lt;br /&gt;
&lt;br /&gt;
==== apply filter to saved events ====&lt;br /&gt;
Beschreibung folgt&lt;br /&gt;
&lt;br /&gt;
==== clear saved event ====&lt;br /&gt;
Es werden alle gespeicherten Events gelöscht.&lt;br /&gt;
&lt;br /&gt;
Ausnahme: Events, die als Trigger eingestellt sind, bleiben erhalten.&lt;br /&gt;
&lt;br /&gt;
=== Affected devices ===&lt;br /&gt;
[[Datei:MSwitch_Screen_5.png|mini|rechts|affected devices]]&lt;br /&gt;
Dieser Abschnitt beinhaltet die Auswahl der Devices, die auf ein Event reagieren sollen.&lt;br /&gt;
&lt;br /&gt;
In dem Auswahlfeld werden alle Devices angeboten, die eines der folgenden Kriterien erfüllen:&lt;br /&gt;
# Die Abfrage &amp;quot;set Device ?&amp;quot; liefert einen Befehlssatz&lt;br /&gt;
# Das Attribut &#039;webcmd&#039; des Devices enthält Einträge&lt;br /&gt;
# Das Attribut &#039;MSwitch_Activate_MSwitchcmds&#039; ist aktiviert und das Attribut &#039;MSwitchcmds&#039; des betreffenden Devices enthält einen Befehlssatz&lt;br /&gt;
&lt;br /&gt;
Einzige Ausnahme ist der erste Listeneintrag &#039;FreeCMD&#039;. Die Auswahl dieses Eintrages bietet später die Möglichkeit Befehle auszuführen, die nicht an ein Device gebunden sind. Der Code in einem FreeCmd kann entweder reiner FHEM-Code sein ( set device on ) oder reiner Perl-Code. Wenn es sich um reinen Perl-Code handelt, ist dieser in geschweifte Klammen zu setzen { Perl-Code }.&lt;br /&gt;
&lt;br /&gt;
=== Device actions ===&lt;br /&gt;
[[Datei:Webinterface3.png|mini|rechts|device_actions]]&lt;br /&gt;
Hier stellt man die auszuführenden Aktionen der eingestellten Devices ein. Im ersten Abschnitt oben befindet sich ein FreeCmd, mit dem beliebige Kommandos eingetragen werden können. Im abgebildeten Beispiel ist dies sogar selbst definierter Perl-Code (die Funktion DebianMail sendet eine Mail). &lt;br /&gt;
&lt;br /&gt;
==== MSwitch cmd1/cmd2:  ====&lt;br /&gt;
Man wählt den Befehl aus dem betreffenden Device aus. Bei freien Textfeldern (wie im Fall des FreeCmd) wird der Befehl eingegeben.&lt;br /&gt;
&lt;br /&gt;
Es werden alle verfügbaren Befehle des Devices zur Auswahl angeboten. Je nach Attribut-Einstellungen werden Einträge aus entsprechenden &#039;webcmds&amp;quot; oder &#039;MSwitchcmds&#039; einbezogen. In Abhängigkeit des Befehls stehen unter Umständen weitere Felder oder Widgets zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
05.04.2018 NEU: Auswahlfeld &#039;MSwitchtoggle&#039; -&amp;gt; Beschreibung wird noch ergänzt !&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 condition  ====&lt;br /&gt;
Mit diesem Feld kann die Ausführung des Befehls von weiteren Bedingungen abhängig gemacht werden. Bei der Abfrage von Readings nach Strings (on, off, etc.) ist statt &amp;quot;=&amp;quot; &amp;quot;eq&amp;quot; zu nutzen und der String muss in &amp;quot;x&amp;quot; gesetzt werden. Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
#Zeitabhängiges schalten: [19:10-23:00] - Schaltbefehl erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
#Readingabhängiges schalten [Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Schaltbefehl erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
&lt;br /&gt;
Soll nur an bestimmten Wochentagen geschaltet werden, muss eine Zeitangabe gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [10:00-11:00|13] den Schaltvorgang nur Montag und Mittwoch zwischen 10 Uhr und 11 Uhr auslösen. Hierbei zählen die Wochentage von 1-7 für Montag-Sonntag.&lt;br /&gt;
&lt;br /&gt;
Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich:&lt;br /&gt;
* [19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
* [19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
* [{sunset()}-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
* { !$we } löst den Schaltvorgang nur Werktagen aus&lt;br /&gt;
* { $we } löst den Schaltvorgang nur Wochenenden, Feiertagen aus&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung:&#039;&#039;&#039; Bei Anwendung der geschweiften Klammern zur Einleitung eines Perl Ausdrucks ist unbedingt auf die Leerzeichen hinter und vor der Klammer zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (zum Beispiel würde auch am Mittwoch noch der Schaltvorgang erfolgen, wenn als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
; $EVENT:&lt;br /&gt;
: Die Variable EVENT enthält den auslösenden Trigger, d.h. es kann eine Reaktion in direkter Abhängigkeit zum auslösenden Trigger erfolgen.&lt;br /&gt;
&lt;br /&gt;
[$EVENT] eq &amp;quot;state:on&amp;quot; würde den Kommandozweig nur dann ausführen, wenn der auslösende Trigger &amp;quot;state:on&amp;quot; war. Wichtig ist dieses, wenn bei den Triggerdetails nicht schon auf ein bestimmtes Event getriggert wird, sondern hier durch die Nutzung eines Wildcards (*) auf alle Events getriggert wird, oder auf alle Events eines Readings z.B. (state:*).&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 delay  ====&lt;br /&gt;
Ein Eintrag in diesem Feld führt zur verzögerten Ausführung des Befehls nach Eintreffen des Events. Dabei kann der Befehl ohne weitere Prüfung der Bedingung ausgelöst werden. Es ist aber auch möglich, dass die Bedingung bei Ausführung erneut geprüft wird. Die Zeitangabe muss im Format hh:mm:ss vorliegen.&lt;br /&gt;
&lt;br /&gt;
Statt einer unmittelbaren Zeitangabe kann hier auch ein Verweis auf ein Reading eines Devices erfolgen :&amp;lt;br&amp;gt;&lt;br /&gt;
[NAME.reading] des Devices -&amp;gt;z.B. [dummy.state]&lt;br /&gt;
&lt;br /&gt;
==== add action  ====&lt;br /&gt;
Mit diesem Button kann ein weiteres Eingabefeld für das entsprechende Device angelegt werden, um z.B. einen weiteren Befehl (ggf.) zeitverzögert auszuführen.&lt;br /&gt;
&lt;br /&gt;
==== delete this action  ====&lt;br /&gt;
Mit diesem Button wird der entsprechende Befehl für das Device gelöscht.&lt;br /&gt;
&lt;br /&gt;
==== check condition  ====&lt;br /&gt;
[[Datei:MSwitch_Screen_7.png|mini|rechts|check]]&lt;br /&gt;
Die angegebenen &#039;conditions&#039; werden in Zusammenhang mit ggf. ausgewählten Devices auf Syntax und Ergebnis geprüft. Es erfolgt eine Ausgabe des Prüfungsergebnisses.&lt;br /&gt;
&lt;br /&gt;
==== Repeat und Repeatdelay ====&lt;br /&gt;
Man kann mehrfache Wiederholungen erzwingen. Repeat gibt dabei an, wie oft das Kommando wiederholt wird (Anzahl). Repeatdelay gibt an, wie viel Sekunden zwischen einzelnen Wiederholungen liegen sollen.&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Folgende Attribute stehen zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Debug (0:1:2:3:4) ===&lt;br /&gt;
0 - Abgeschaltet&amp;lt;br&amp;gt;&lt;br /&gt;
1 - Schaltet Felder zum testen der Conditionstrings etc. an&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Alle ausgehenden Befehle werden nur simuliert und nicht ausgeführt. Es erfolgt eine Protokollierung in einer separaten Datei . Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Es erfolgt eine Protokollierung in einer separaten Datei . Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
4 - erweiterte Debugfunktion (nur für Entwicklung - wechselnde Funktion )&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Expert (0:1) ===&lt;br /&gt;
In der Liste der möglichen Trigger erscheint das Selectfeld &#039;GLOBAL&#039;. Dieses ermöglicht das Setzen eines Triggers auf alle Events und damit nicht nur auf einzelne Devices. In einem weiteren Feld kann eine weitere Selektion der triggernden Events erfolgen.&lt;br /&gt;
&lt;br /&gt;
Es stehen weitere Felder &#039;Repeats&#039; und &#039;Repeatdelay in sec&#039; zur Verfügung. Eine hier getätigte Einstellung bewirkt X-fache Wiederholung von gesetzten Befehlen im Abstand der gesetzten Sekunden.&lt;br /&gt;
&lt;br /&gt;
Weiterhin kann über das Auswahlfeld &#039;priotity&#039; bei jedem &#039;affectes device&#039; die Reihenfolge beim abarbeiten der Befehle beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequenz &amp;lt;Suchmuster&amp;gt; ===&lt;br /&gt;
In diesem Attribut können ein oder mehrere Suchmuster angegeben werden ,die eine Schaltsequenz darstellen und vom Device erkannt werden.&lt;br /&gt;
&lt;br /&gt;
Die Angabe muss folgende Syntax haben:&lt;br /&gt;
:&amp;lt;code&amp;gt;Device1:reading1:event1 Device1:reading1:event1-2 Device1:reading1:event1-3/..../....&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mehrere Suchmuster müssen durch &amp;quot;/&amp;quot; getrennt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
:&amp;lt;code&amp;gt;Dummy:state:on Dummy:state:off Dummy:state:on&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erkennt das Device dieses Suchmuster in den Schaltvorgängen des Devices (Dummy), wird das Reading &amp;quot;SEQUENCE&amp;quot; auf &amp;quot;match&amp;quot; gesetzt, das Reading &amp;quot;SEQUENCE_NUMBER&amp;quot; auf die Nummer der gefundenen Sequenz, wenn es mehrere Suchmuster gibt. Beide Readings können in den &amp;quot;Conditions&amp;quot; eines Schaltbefehles abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequence_time &amp;lt;Zeit in Sekunden&amp;gt; ===&lt;br /&gt;
Beinhaltet die Zeit in Sekunden, die es dauern darf, um eine Sequenz vollständig auszuführen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Extensions (0:1) ===&lt;br /&gt;
Es wird eine zusätzliche Schaltoption &#039;MSwitchToggle&#039; in den Geräten angeboten. Diese kann genutzt werden, wenn zuschaltende Geräte eine Togglefunktion nicht von Haus aus anbieten.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe muss in folgendem Format gemacht werden:&lt;br /&gt;
:&amp;lt;code&amp;gt;on/off/state/suchmuster1/suchmuster2&amp;lt;/code&amp;gt;, wobei die letzten drei Angaben optional sind.&lt;br /&gt;
&lt;br /&gt;
Funktion: Bei Ausführung des Befehls wird das Gerät &#039;on&#039; oder &#039;off&#039; geschaltet (on/off), Voraussetzung ist, dass der &#039;state&#039; dieses Gerätes auch den &#039;state on&#039; oder &#039;off&#039; annimmt. Sollte dieses nicht der Fall sein, so kann mit dem Feld &#039;state&#039; angegeben werden, in welchem Reading der aktuelle Status vorkommt und wie dieser lautet (suchmuster1/suchmuster2). Dieses &#039;state&#039; kann mehrere Angaben enthalten, das Vorkommen der Suchmuster ist aber Voraussetzung.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Delete_Delays (0:1) ===&lt;br /&gt;
Bewirkt das Löschen aller anstehende Timer (Delays) bei dem Auftreten eines erneuten, passenden Events. Bei der Option &#039;0&#039; bleiben bereits gesetzte Delays aus einem vorherigen, getriggertem Event erhalten und werden ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1)&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Devicecmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz liefern (bei Abfrage set DEVICE ?).&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Webcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut Webcmd hinterlegt haben. Die in Webcmd hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten.&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Activate_MSwitchcmds (0:1) ===&lt;br /&gt;
Fügt jedem vorhandenen Device as Attribut &#039;MSwitchcmd&#039; hinzu.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_MSwitchcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut MSwitchcmds hinterlegt haben. Die in MSwitchcmds hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten. Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr Angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Lock_Quickedit (0:1) ===&lt;br /&gt;
Voreinstellung für die Auswahlliste &#039;Affected Devices&#039;. Bei der Option (1) ist diese voreingestellt gesperrt und kann nur über einen zusätzlichen Button geändert werden. Da es sich hier um ein Feld mit der Möglichkeit einer Mehrfacheingabe handelt handelt ist die Voreinstellung 1, um versehentliche nicht gewünschte Änderungen zu vermeiden (Auswahl einer Option ohne &#039;Strg&#039; bewirkt das löschen aller bereits gesetzten Optionen).&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay (0:10:20:30:60) ===&lt;br /&gt;
Diese Einstellung beeinflusst den Start von MSwitch nach einem FHEM Start. MSwitch ignoriert für die angegebene Zeit in Sekunden alle eingehenden Events um u.a. Startverzögerungen zu vermeiden. Bei nicht gesetztem Attribut gilt hier eine Zeit von 30 Sekunden. Diese sollte auch nur in Ausnahmefällen bzw. bei besonderem Bedarf geändert werden.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (30).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Ignore_Types ===&lt;br /&gt;
Beinhaltet eine Liste von Device&#039;&#039;typen&#039;&#039;, die in den Auswahllisten &#039;&#039;nicht&#039;&#039; dargestellt werden. Hier ist es sinnvoll, Devicetypen einzutragen, die in aller Regel nicht geschaltet werden oder nicht geschaltet werden können, um die Auswahllisten übersichtlicher zu halten. Einzelne Devicetypen sind durch Leerzeichen zu trennen.&lt;br /&gt;
&lt;br /&gt;
Voreinstellung: notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe kann hier in 2 Arten getätigt werden:&lt;br /&gt;
# eine Liste von devicetypen.&lt;br /&gt;
# Angabe einer devspec z.B. &amp;quot;TYPE=watchdog&amp;quot;. Hier ist zu beachten, dass in diesem Fall alle Geräte in die Ignoreliste einbezogen werden, die NICHT der devspec entsprechen. Weiterhin muss die devspec in Anführungszeichen gesetzt werden!&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Trigger_Filter ===&lt;br /&gt;
Beinhaltet eine Liste von Events, die bei eingehenden Events unberücksichtigt bleiben. Diese werde dann auch nicht gespeichert.&lt;br /&gt;
&lt;br /&gt;
Hier kann mit Wildcards (*) gearbeitet werden. Einzelne Events sind durch Komma &#039;,&#039; zu trennen.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (keine).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Wait (sec)===&lt;br /&gt;
Bei gesetztem Attribut (Zeit in Sekunden) nimmt Das MSwitch Device für den eingestellten Zeitraum keine Befehle mehr entgegen und ignoriert eingehende Events&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Event_Id_Distributor ===&lt;br /&gt;
Dieses Attribut hat nur dann eine Funktion, wenn auch das Attribut &#039;MSwitchExpert&#039; auf &#039;1&#039; gesetzt ist.&lt;br /&gt;
Hier können verschiedene auslösende Events auf Aktionen mit angegebenen IDs umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Sollte bei den &#039;trigger details :&#039; in einem Zweig ( cmd1 ) z.B. auf mehrere Events getriggert werden ( regex z.B. state:(on|off) ) so werden für beide Events jeweils der Zweig &#039;cmd1&#039; - alle  Aktionen ohneID - ausgeführt. Durch entsprechende Einträge kann für entsprechende Events auf eine Aktion umgeleitet werden, für die eine ID definiert ist. Die Syntax lautet:&lt;br /&gt;
:&amp;lt;code&amp;gt;state:on=&amp;gt;cmd1 ID 1,2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden bei auslösendem Event &#039;state:on&#039; nur die Aktionen aus cmd1 mit den IDs 1 und 2 ausgeführt. Mehrere Angaben sind durch new Line zu trennen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Selftrigger_always (0,1)===&lt;br /&gt;
(dieses Attribut steht ab Modulversion 2.5 zur Verfügung)&lt;br /&gt;
&lt;br /&gt;
Die Aktivierung dieses Attributes (1) bewirkt, dass alle SET Aktionen des Devices einen (internen) Event auslösen, auf die das Device selber reagiert. Diese Option kann zusätzlich zu einem vorhandenen Trigger aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Diese Events sind lediglich Device intern, d.h es werden keine Modulübergreifenden Events ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Auftretende und auswertbare interne Events haben immer folgendes Format und können darüber ausgewertet werden.&lt;br /&gt;
&lt;br /&gt;
MSwitch_Self:aktion:wert &lt;br /&gt;
MSwitch_Self:pct:100&lt;br /&gt;
&lt;br /&gt;
Es werden nur interne Events für set-Aktionen ausgelöst, die im Attribut setlist hinterlegt sind.&lt;br /&gt;
&lt;br /&gt;
Als weitere Besonderheit unterliegen diese internen Events nicht dem &#039;wait&#039; Befehl/Attribut&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Mode (Notify,Full,Toggle,Dummy)===&lt;br /&gt;
Schaltet das Modul zwischen verschiedenen Modi um, mit entsprechend angepasster Weboberfläche.&lt;br /&gt;
&lt;br /&gt;
==== Notify ====&lt;br /&gt;
Das Device kann nicht manuell umgeschaltet werden, es gibt nur zwei ausführbare Zweige (execute &#039;cmd1&#039; commands und execute &#039;cmd2&#039; commands). Der Status des Devices wird nicht als &#039;on&#039; oder &#039;off&#039; angezeigt, sondern lediglich als &#039;active&#039;&lt;br /&gt;
&lt;br /&gt;
Dieser Mode ist am ehesten mit einem Notify zu Vergleichen.&lt;br /&gt;
==== Full ====&lt;br /&gt;
Es stehen alle Funktionen zur Verfügung.&lt;br /&gt;
==== Toggle ====&lt;br /&gt;
Sehr vereinfachter Mode. Es stehen keine verschiedenen Zweige zur Verfügung. Hier ist das Device manuell schaltbar und wird bei jedem definierten Event &#039;Umgeschaltet&#039;, entsprechend definierte Befehle für &#039;cmd1&#039; oder &#039;cmd2&#039; werden ausgeführt.&lt;br /&gt;
==== Dummy====&lt;br /&gt;
ACHTUNG: Funktionsänderung mit V2.61&lt;br /&gt;
&lt;br /&gt;
Der Mode &#039;Dummy&#039; ist ein eingeschränkter Modus. &lt;br /&gt;
Dieser bietet die Funktionalität eines Dummys kombiniert mit der Funktionalität eines Notifys und kann somit die gerne genutzte Kombination Dummy-Notify gegen ein Device ersetzen.&lt;br /&gt;
&lt;br /&gt;
Achtung: Devices die einmal in dem Modus &#039;Dummy&#039; gesetzt wurden können nicht wieder in einen anderen Mode geschaltet werden ! &lt;br /&gt;
&lt;br /&gt;
Der Dummy-Mode kann nur in einem neu angelegtem, leeren MSwitch aktiviert werden. Sobald ein angelegtes MSwitch einmal verändert wurde (modify trigger etc.) ist ein Umschalten nicht mehr möglich und die Option nicht mehr verfügbar.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Condition_Time (0,1)===&lt;br /&gt;
In der Grundeinstellung (0) werden für das zeitgesteuerte Schalten keine definierten Conditionen im Feld &#039;Trigger condition&#039; überprüft, sondern die Schaltbefehle werden in jedem Fall ausgeführt. Mit der Einstellung (1) wird diese Überprüfung auch für zeitgesteuerte Befehle zugeschaltet.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Time (HH:MM:SS-HH:MM:SS)===&lt;br /&gt;
Bei Aktivierung wird vor jedem Ausführen eines verzögerten Befehls ( Delay ) eine Zufallszeit generiert, die im Rahme der hier angegebenen Zeitspanne liegt. Auf diese Zufallszahl kann in den Delays zugegriffen werden, durch die Angabe &#039;[random]&#039; statt einer direkten Zeitangabe. Bei nicht gesetztem Attribut ergibt die Angabe von &#039; [random] &#039; hier immer &#039;00:00:00&#039;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Number ===&lt;br /&gt;
Bei Aktivierung dieses Attributes (der Inhalt kann einen beliebige Zahl sein) werden vom Device 2 Readings angelegt (Device:RandomNr) und (Device:RandomNr1). RandomNr wird vor jedem Ausführen eines Befehls aktualisiert und neu generiert, d.h wenn ein MSwitch Device mehrere Geräte schaltet, wird (auch in einem Durchgang) vor jedem Befehl dieses Reading neu gesetzt. RandomNr1 wird lediglich bei Ausführung des MSwitch Devices einmal neu gesetzt, d.h. nicht vor jedem Befehl der ausgeführt wird.&lt;br /&gt;
Die Readings werden mit einer Zufallszahl zwischen 0 und dem hier eingestellten Wert gesetzt.&lt;br /&gt;
&lt;br /&gt;
Auf diese Readings kann in jeder Condition mit z.B. &#039;[$NAME:ReadingNr1] = 1&#039; zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
D.h., das in der Condition angegebene Reading ( [$NAME:ReadingNr1] ) muss in diesem Fall den Wert 1 angenommen haben, ansonsten wird der Befehl nicht ausgeführt. &lt;br /&gt;
Der Befehl wird somit nur mit einer Wahrscheinlichkeit von 1 zu ( gesetzter Wert im Attr. ) ausgeführt.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Reset_EVT_CMD1(2)_COUNT ===&lt;br /&gt;
Bei Aktivierung dieses Attributes steht in den Readings das Reading &#039;EVT_CMD1_COUNT&#039; bzw. &#039;EVT_CMD2_COUNT&#039; zur Verfügung. Dieses kann in den Conditions genutzt werden, um z.B. nur bei jedem x-ten Eintreffen eines auslösenden Events einen Befehl auszuführen. Bei jedem Eintreffen eines gültigen Events werden die Zähler um 1 erhöht (für den jeweiligen Zweig). &lt;br /&gt;
Ist hier der Wert &#039;0&#039; eingetragen, wird der Zähler fortlaufend (endlos) erhöht. Wird ein Wert größer 0 eingetragen, wird der Zähler mit Erreichen dieses Wertes automatisch wieder auf Null gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit Löschen dieses Attributes werden die entsprechenden Readings ebenfalls gelöscht.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Safemode (0:1)===&lt;br /&gt;
Bietet einen (gewissen) Schutz vor falschen Konfigurationen und somit entstehenden Endlosschleifen.&lt;br /&gt;
Bei aktiviertem Attribut (1) erkennt das Modul Endlosschleifen eines Devices und beendet diese.&lt;br /&gt;
&lt;br /&gt;
In diesem Fall erfolgt ein Logeintrag und das Device wird per Attribut auf &#039;Disabled&#039; gesetzt.&lt;br /&gt;
Es wird ein letztes Event generiert, auf das reagiert werden kann:&lt;br /&gt;
:&amp;lt;code&amp;gt;2018-05-31 09:39:21 MSwitch &amp;lt;NAME&amp;gt; Safemode: on&amp;lt;/code&amp;gt;&lt;br /&gt;
Im Webinterface erfolgt bei betroffenem Device ein entsprechender Hinweis.&lt;br /&gt;
&lt;br /&gt;
In der Grundkonfiguration ist dieses Attribut nicht gesetzt, es empfiehlt sich aber, bei neuen (komplizierten) Devices, dieses - zumindest anfänglich - zu aktivieren.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Read_Log(0:1)===&lt;br /&gt;
Ermöglicht den Zugriff auf das Logfile als Trigger.&lt;br /&gt;
&lt;br /&gt;
Hier gibt es mehrere Konfigurationsmöglichkeiten:&lt;br /&gt;
* Bei aktiviertem Attribut enthält die Auswahl des Triggerdevices die Option &#039;LOGFILE&#039;. Bei dieser Auswahl werde alle Logeinträge erkannt und in ein internes Event umgewandelt, auf das regiert werden kann.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl &#039;GLOBAL&#039; im &#039;Trigger_Device&#039; wird auf ALLE Events und alle Logeinträge reagiert.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl eines bestimmten Devices im &#039;Trigger_Device&#039; wird auf alle Events  und auf alle Logeinträge des gewählten Devices reagiert. Hier ist zu beachten, dass FHEM mir keine Möglichkeit bietet, wirklich herauszufinden, welches Device denn nun einen Logeintrag generiert hat. D.h., dieses wird vom Vorhandensein des Namens im Logeintrag abhängig gemacht und MSwitch reagiert nur dann auf einen Logeintrag, wenn der Name des Devices in diesem Eintrag vorhanden ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Help(0:1)===&lt;br /&gt;
Schaltet Hilfebuttons zu den einzelnen Eingabefeldern an oder aus.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Comments(0:1)===&lt;br /&gt;
Schaltet Kommentarfelder zu den einzelnen &#039;affected_devices an.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_generate_Events(0:1)===&lt;br /&gt;
Reduziert bei Einstellung &#039;1&#039; die vom MSwitch-Devices erzeugten Events auf ein absolutes Minimum. Insbesondere bei Verwendung von &#039;MSwitch_Read_Log&#039; zu empfehlen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay ===&lt;br /&gt;
Bestimmt die Verzögerungszeit des MSwitches nach FHEM-Start in Sekunden. In diesem Zeitraum reagiert das ??Event??(Red: ist hier &amp;quot;Device&amp;quot; gemeint?) nicht auf Events. Die Vorgabe ist hier zehn Sekunden. Diese wird auch dann angenommen, wenn das Attribut nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Inforoom ===&lt;br /&gt;
Mit diesem Attribut wird die Raumansicht eines mit dem Attribut bestimmten Raumes verändert. Dadurch sollen die wichtigsten Informationen aller MSwitch-Devices auf eine Seite dargestellt werden. Zur Nutzung sollten alle MSwitch-Devices (zusätzlich) in einen Raum sortiert werden und dieser Raum im Attribut eingestellt werden.&lt;br /&gt;
&lt;br /&gt;
Wichtig: Eine Änderung dieses Attributes bewirkt immer eine Änderung dieses Attributes in &#039;&#039;allen&#039;&#039; MSwitch devices: Es muss nur in einem Device gesetzt oder gelöscht werden um alle Devices zu erfassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
MSwitch_Screen_1.png|Raumansicht des Raumes MSwitch mit gesetztem Attribut &#039;MSwitch&#039;&lt;br /&gt;
MSwitch_Screen_2.png|Raumansicht des Raumes MSwitch ohne gesetztes Attribut&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es werden folgende Informationen bereitgestellt:&lt;br /&gt;
* Infobutton zeigt den im Device gespeicherten Textes des Attributes &#039;comment&#039;&lt;br /&gt;
* Device und Events, die das Device triggern&lt;br /&gt;
* Zeiten, zu denen verschiedene Zweige des Devices ausgeführt werden&lt;br /&gt;
* Devices, die durch das MSwitch Device geschaltet werden&lt;br /&gt;
* State des Devices&lt;br /&gt;
&lt;br /&gt;
== Integrierte Funktionen ==&lt;br /&gt;
&lt;br /&gt;
=== Average ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
=== Tendency ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[TEND&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;Mindestwert&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[TEND2:countdown] &amp;gt; 2&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Es wird jeweils der Durchschnitt von 2 Wertepaaren gebildet. In diesem Fall werden die letzten 4 Werte herangezogen.&amp;lt;br&amp;gt;&lt;br /&gt;
Paar 1 = Aktueller und letzter Wert, Paar 2 = Die 2 vorherigen Werte.&amp;lt;br&amp;gt;&lt;br /&gt;
Bei TEND3 werden die letzten 6 Werte zur Paarbildung genutzt.&lt;br /&gt;
&lt;br /&gt;
Mindestwert:&lt;br /&gt;
Der Wertunterschied zwischen den Wertepaaren, der minimal erreicht sein muss, um eine Tendenz zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Rechenzeichen (&amp;gt;&amp;lt;):&lt;br /&gt;
Dieses ist hier nicht als Rechenzeichen zu werten, sonder als Tendenz-Anzeige. ( &amp;lt; es wird nach fallender Tendenz gesucht / &amp;gt; sucht nach steigender Tendenz).&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolgt einmalig bei Erkennung der gesuchten Tendenz.&lt;br /&gt;
Danach erfolgt keine Schaltung mehr, solange bis eine Tendenz-Umkehr erfolgt ist.&lt;br /&gt;
Erst dann erfolgt wieder eine Schaltung bei erneuter Tendenz-Umkehr in gesuchte Richtung.&lt;br /&gt;
&lt;br /&gt;
=== Difference ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[DIFF&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;differenz&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[DIFF2:countdown] &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Gespeicherter Wert (in diesem Fall der vorletzte).&lt;br /&gt;
&lt;br /&gt;
Differenz:&lt;br /&gt;
Geforderter Differenz zwischen aktuellem und vorletztem Wert.&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolg wenn diese Bedingung &#039;wahr&#039; ist.&lt;br /&gt;
&lt;br /&gt;
Folgende Readings werden zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
DIFFERENCE (true/false) - Schaltbedingung erkannt ja/nein&lt;br /&gt;
&lt;br /&gt;
DIFFDIRECTION (up/down) - Richtung der erkannten Bedingung (steigend/fallend)&lt;br /&gt;
&lt;br /&gt;
=== Increase ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
== Tipps, Tricks, Kurzbeispiele ==&lt;br /&gt;
Wird stetig ergänzt .&lt;br /&gt;
&lt;br /&gt;
=== Blinken - Falls nicht im Device vorhanden ===&lt;br /&gt;
[[Datei:MSwitch MSwitchblink.png|center|704px]]&lt;br /&gt;
&amp;lt;br clear=all&amp;gt;&lt;br /&gt;
Lässt ein beliebiges Device 5 mal togglen, mit einem Intervall von 0.5 Sekunden (Blinkzeit somit 2,5 Sekunden)&amp;lt;br&amp;gt;&lt;br /&gt;
Die MSwitchtoggle-Funktion muss per ATTR aktiviert werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Die Repeatfunktion ist nur im Expertmode verfügbar, auch per ATTR einstellbar.&lt;br /&gt;
&lt;br /&gt;
=== Linearschalter ===&lt;br /&gt;
Umsetzung eines Linearschalters mit MSwitch.&lt;br /&gt;
&lt;br /&gt;
Eingang: Beliebiges Reading als numerischer Wert.&lt;br /&gt;
&lt;br /&gt;
Ausgang: Wird entsprechend Linear / oder umgekehrt Linear zum Eingang geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgend die Rawdefinition des MSwitchdevices und zweier Dummys (selbsterklärend)&lt;br /&gt;
&lt;br /&gt;
Alle Devices werden im Raum Lineartest angelegt, die Dummy müssen zuerst angelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod linearausgang dummy&lt;br /&gt;
attr linearausgang room Lineartest&lt;br /&gt;
attr linearausgang setList state:slider,0,1,100&lt;br /&gt;
attr linearausgang webCmd state&lt;br /&gt;
setstate linearausgang state 57&lt;br /&gt;
setstate linearausgang 2018-06-06 18:06:12 state state 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod lineareingang dummy&lt;br /&gt;
attr lineareingang room Lineartest&lt;br /&gt;
attr lineareingang setList state:slider,0,1,15000&lt;br /&gt;
attr lineareingang webCmd state&lt;br /&gt;
setstate lineareingang 6422&lt;br /&gt;
setstate lineareingang 2018-06-06 18:06:12 state 6422&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod Linearschalter MSwitch lineareingang  # linearausgang FreeCmd&lt;br /&gt;
attr Linearschalter MSwitch_Debug 0&lt;br /&gt;
attr Linearschalter MSwitch_Delete_Delays 1&lt;br /&gt;
attr Linearschalter MSwitch_Expert 0&lt;br /&gt;
attr Linearschalter MSwitch_Extensions 0&lt;br /&gt;
attr Linearschalter MSwitch_Help 0&lt;br /&gt;
attr Linearschalter MSwitch_Ignore_Types notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
attr Linearschalter MSwitch_Include_Devicecmds 1&lt;br /&gt;
attr Linearschalter MSwitch_Include_MSwitchcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Include_Webcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Inforoom MSwitch&lt;br /&gt;
attr Linearschalter MSwitch_Lock_Quickedit 1&lt;br /&gt;
attr Linearschalter MSwitch_Mode Notify&lt;br /&gt;
attr Linearschalter room Lineartest&lt;br /&gt;
&lt;br /&gt;
setstate Linearschalter active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:03:50 .Device_Affected FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:04:35 .Device_Affected_Details FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 );;my $emin=0;;my $emax=15000;;my $amin=100;;my $amax=0;;$eingang = $emin if $eingang &amp;lt; $emin;;$eingang = $emax if $eingang &amp;gt; $emax;;my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin;;readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 );;},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter:to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 .Device_Events no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .First_init done&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_on *&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_condition &lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_on no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_time &lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .V_Check V 0.3&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVENT state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTFULL lineareingang:state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART1 lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART2 state&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART3  6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 Exec_cmd set linearausgang state [Linearschalter:to_set]&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 Trigger_device lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 Trigger_log off&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 last_event state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:39:56 state active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 to_set 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
MSwitch -Configfile (bei Bedarf)&lt;br /&gt;
&amp;lt;pre&amp;gt;#V V1.54&lt;br /&gt;
#S .Device_Affected -&amp;gt; FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
#S .Device_Affected_Details -&amp;gt; FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 )[S]my $emin=0[S]my $emax=15000[S]my $amin=100[S]my $amax=0[S]$eingang = $emin if $eingang &amp;lt; $emin[S]$eingang = $emax if $eingang &amp;gt; $emax[S]my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin[S]readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 )[S]},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter.to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
#S .Device_Events -&amp;gt; no_trigger&lt;br /&gt;
#S .First_init -&amp;gt; done&lt;br /&gt;
#S .Trigger_Whitelist -&amp;gt; undef&lt;br /&gt;
#S .Trigger_cmd_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_cmd_on -&amp;gt; *&lt;br /&gt;
#S .Trigger_condition -&amp;gt; &lt;br /&gt;
#S .Trigger_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_on -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_time -&amp;gt; &lt;br /&gt;
#S .V_Check -&amp;gt; V 0.3&lt;br /&gt;
#S Trigger_device -&amp;gt; lineareingang&lt;br /&gt;
#S Trigger_log -&amp;gt; off&lt;br /&gt;
#S last_event -&amp;gt; state: 6422&lt;br /&gt;
#S state -&amp;gt; active&lt;br /&gt;
#A MSwitch_Ignore_Types -&amp;gt; notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
#A MSwitch_Include_MSwitchcmds -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Debug -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Help -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Devicecmds -&amp;gt; 1&lt;br /&gt;
#A MSwitch_Extensions -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Webcmds -&amp;gt; 0&lt;br /&gt;
#A room -&amp;gt; Lineartest&lt;br /&gt;
#A MSwitch_Inforoom -&amp;gt; MSwitch&lt;br /&gt;
#A MSwitch_Expert -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Lock_Quickedit -&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Thread über das Modul im {{Link2Forum|Topic=86199|LinkText=FHEM Forum}}&lt;br /&gt;
* {{Link2Forum|Topic=100119|Message=936495|LinkText=Gäste-WLAN der Fritzbox auswerten und Login per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=86199|Message=930133|LinkText=Schalten von vier Kanälen mit einem MSwitch-Device}}&lt;br /&gt;
* {{Link2Forum|Topic=99219|Message=926652|LinkText=Batterie-Überwachung. 1xTäglich per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=101091|Message=945389|LinkText=Licht (Alarm) in einem bestimmten Zeitraum schalten}}&lt;br /&gt;
* {{Link2Forum|Topic=100949|Message=944284|LinkText=Über Dummy-Schalter ein Timer (EIN/AUS) aktivieren}}&lt;br /&gt;
* {{Link2Forum|Topic=103083|Message=967710|LinkText=Ladezeit von Akku ermitteln u. Steckdose entsprechend schalten}}&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31475</id>
		<title>MSwitch</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31475"/>
		<updated>2019-11-01T19:59:21Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* MSwitch_Selftrigger_always (0,1) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[MSwitch]] ist ein Hilfsmodul, welches das Event- und/oder zeitgesteuerte Schalten von mehreren Devices oder das Ausführen von benutzerdefinierten Befehlssequenzen erlaubt.&lt;br /&gt;
&lt;br /&gt;
Die Stärke bzw. das Unterscheidungsmerkmal dieses Moduls liegt in der Konfigurierbarkeit über ein Webinterface. Diese Konfiguration kann jederzeit geändert oder erweitert werden. &lt;br /&gt;
&lt;br /&gt;
Byte09: &#039;&#039;Die Grundidee zu MSwitch kam mir, weil ich bei der Arbeit mit FHEM für meinen Geschmack zu viele Module für die verschiedenen Aufgaben brauchte - zu allem Überfluss alle mit unterschiedlicher Syntax. Zwar ist DOIF hiervon ausgenommen (da hiermit wohl auch fast jede Aufgabe lösbar ist), aber ich konnte mich leider nicht daran gewöhnen und somit wurde jedes DOIF für mich zu einem echten Projekt. Was ich wollte war ein Modul, mit dem ich alles erledigen kann. Daher entschloss ich mich schon nach fast einem knappen Jahr FHEM-Nutzung mein eigenes Modul zu schreiben, welches diese Anforderung erfüllt. MSwitch beinhaltet die Funktionalität aller bisherigen Hilfsmodule wie z.B. Notify, Doif, Watchdog, Dummy,( ab Modulversion 2.2 auch Sequenz ) es lassen sich all deren Funktionen umsetzen.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;MSwitch wird permanent - vorrangig nach meinen Bedürfnissen - weiterentwickelt, gerne nehme ich aber auch Anregungen von anderen Nutzern auf.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=MSwitch&lt;br /&gt;
|ModType=h&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=98_MSwitch.pm&lt;br /&gt;
|ModOwner=Byte09}}&lt;br /&gt;
&lt;br /&gt;
== Grundsätzliche Überlegungen ==&lt;br /&gt;
Um das Modul zu nutzen, muss man zuerst folgende Fragen beantworten:&lt;br /&gt;
&lt;br /&gt;
* Welches Gerät soll auslösen oder zu welcher Zeit soll eine Auslösung erfolgen.&lt;br /&gt;
: Dies ist der Trigger. Jedes Event aus dem Eventmonitor kann als Trigger dienen. Will man mehrere Geräte als gleichzeitige Auslöser betreiben, so muss das Device GLOBAL gewählt und die entsprechenden Geräte angegeben werden (dies erzeugt höhere Systemlast und ist nur im Expert-Modus verfügbar). Weiterhin kann auch zu fest definierten Zeiten, Zufallszeiten oder Intervallen, unabhängig von einem Trigger, geschaltet werden; auch eine Kombination beider Varianten ist möglich. Diese Einstellungen erfolgen im ersten Teil des Webinterfaces.&lt;br /&gt;
&lt;br /&gt;
* Welche Bedingungen sollen bei Auslösung erfüllt sein?&lt;br /&gt;
: Wenn diese Bedingungen erfüllt sind, werden Kommandos ausgelöst. Die Bedingungen werden im zweiten Teil des Webinterfaces eingegeben. Dabei unterscheidet das Modul zwischen zwei Kommando-Kanälen (cmd1 und cmd2) und den dazugehörigen Geräten.&lt;br /&gt;
&lt;br /&gt;
* Welche Kommandos sollen ausgelöst werden?&lt;br /&gt;
: Im dritten Teil des Webinterfaces werden dann die konkreten Kommandos eingegeben. Typischerweise wählt man dabei aus einer Liste der Kommandos aus, die die zugehörigen Geräte insgesamt aufweisen (also so, wie man auf den Geräteseiten selber Kommandos auswählt). Es gibt zudem ein so genanntes FreeCmd, das ein Geräteunabhängiges Kommando zulässt, beispielsweise reinen Perl-Code.&lt;br /&gt;
&lt;br /&gt;
* Welche weiteren Bedingungen sollen noch gelten?&lt;br /&gt;
: Hier sind Ereignisgesteuerte wie auch Zeitgesteuerte Bedingungen möglich. Diese Bedingungen werden auch in dem dritten Teil des Webinterfaces eingetragen. So sind Verzögerungen und Wiederholungen und weitere Bedingungen möglich.&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen, Installation und Grundbefehle ==&lt;br /&gt;
Das MSwitch-Modul ist ohne weitere Voraussetzungen nutzbar und wird derzeit in der Version 2.08 über FHEM Update verteilt. &lt;br /&gt;
&lt;br /&gt;
=== Definition und Einrichtung ===&lt;br /&gt;
Mit Hilfe von MSwitch kann man mehrere Devices gleichzeitig schalten. Diese Schaltungen befinden sich in zwei möglichen Zweigen bei MSwitch. Dabei unterscheidet man im Modul zwischen den beiden Kommandos cmd1 und cmd2. Die zu einem Kommando gehörenden Geräte werden wir auch Zweig nennen. Die einzelnen Devices jedes Zweiges können mit weiteren Schaltbedingungen versehen werden (zeit- oder ereignisgesteuert). &lt;br /&gt;
&lt;br /&gt;
Folgende Möglichkeiten zum definieren des MSwitch Devices stehen zur Verfügung:&lt;br /&gt;
:&amp;lt;code&amp;gt;define &amp;lt;name&amp;gt; MSwitch&amp;lt;/code&amp;gt;&lt;br /&gt;
Es wird ein leeres Device angelegt, das dann komplett über das Webinterface konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das define eines MSwitch Devices generiert lediglich eine &#039;leere Hülle&#039;. Alle relevante Einstellungen werden in Readings und/oder Hashes gespeichert. Daher stehen relevanten Daten &#039;&#039;nicht&#039;&#039; in der fhem.cfg! Vielmehr finden sich diese Daten in der Datei fhem.save (die Speicherung erfolgt durch den Befehl Fhemsave).&lt;br /&gt;
&lt;br /&gt;
=== set-Befehle ===&lt;br /&gt;
Es sind derzeit die folgenden set-Befehle implementiert.&lt;br /&gt;
&lt;br /&gt;
==== set active ====&lt;br /&gt;
Setzt das Device in den Status &#039;active&#039;.&lt;br /&gt;
&lt;br /&gt;
==== set inactive ====&lt;br /&gt;
Setzt das Device in den Status &#039;inactive&#039;, es werden keine Befehle mehr ausgeführt. Dieser Status entspricht dem Attribut &#039;disable&#039;, ist aber nicht mit dem roten Fragezeichen (fhem save) verbunden.&lt;br /&gt;
&lt;br /&gt;
==== set on/off [&amp;lt;parameter&amp;gt;]====&lt;br /&gt;
Setzt das Device in den Status &#039;on&#039; oder &#039;off&#039;. Alle Befehle der &#039;on/off-Zweige&#039; werden ausgeführt.&lt;br /&gt;
Optional kann den Befehlen &#039;on&#039; und &#039;off&#039; ein weiterer Parameter mit übergeben werden. Dieser wird im Reading &#039;Parameter&#039; hinterlegt und es kann sofort in &#039;Freecmds&#039; oder &#039;Conditions&#039; darauf zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
==== set reload_timer ====&lt;br /&gt;
Alle gesetzten Timer werden gelöscht und neu berechnet.&lt;br /&gt;
&lt;br /&gt;
==== set change_renamed &amp;lt;oldname&amp;gt; &amp;lt;newname&amp;gt; ====&lt;br /&gt;
Sollten sich Devicenammen im ausführenden Teil geändert habe (affected Devices, Conditions, etc.) so kann das MSwitch mit diesem Befehl angepasst werden, ohne alle Einstellungen neu einstellen zu müssen.&lt;br /&gt;
&lt;br /&gt;
==== set exec_cmd1 / set exec_cmd1 ID [&amp;lt;ID&amp;gt;] ====&lt;br /&gt;
Bewirkt das sofortige Ausführen des entsprechenden Befehlszweiges. Bei Angabe einer ID werden nur die Befehle mit der entsprechenden ID ausgeführt.&lt;br /&gt;
&lt;br /&gt;
==== set MSwitch_backup ====&lt;br /&gt;
Erstellt eine Backup-Datei aller MSwitch Devices unter ./fhem/MSwitch_backup.cfg.&lt;br /&gt;
&lt;br /&gt;
Daten dieser Datei können im Bedarfsfall für einzelne oder gleichzeitig alle MSwitch Devices wieder zurückgespielt (hergestellt) werden.&lt;br /&gt;
&lt;br /&gt;
==== set del_delays ====&lt;br /&gt;
Löscht alle anstehenden, verzögerten Befehle (delays).&lt;br /&gt;
&lt;br /&gt;
==== set reset_cmd_count:1,2 ====&lt;br /&gt;
Löscht das entsprechende EVT_CMD_COUNT - Reading (entspricht Rückstellung auf &#039;0&#039;).&lt;br /&gt;
&lt;br /&gt;
==== set fakeevent [&amp;lt;device&amp;gt;]:&amp;lt;reading&amp;gt;:&amp;lt;arg&amp;gt; ====&lt;br /&gt;
Beispiel: &amp;lt;device&amp;gt; fakeevent state:on&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ob der Name (&amp;lt;device&amp;gt;) angegeben werden muss, oder nicht, ist abhängig davon, ob auf ein einzelnes Device, oder GLOBAL getriggert wird. Bei GLOBALEN Triggern muss das Device mit angegeben werden. Wird auf ein Device getriggert, so wird das Device automatisch gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit diesem Befehl kann das MSwitch Device neu getriggert werden, indem hier ein Event &#039;gefaked&#039; wird. Das MSwitch Device reagiert dann so, als wäre dieses Event vom getriggerten Gerät generiert worden. &lt;br /&gt;
&lt;br /&gt;
Dieses kann nötig sein, um z.B. einen Watchdog zu realisieren, in dem es nötig ist, dass sich das MSwitch Device mit einem bestimmten Event selber neu triggert - ggf. mit einem entsprechenden Delay (affected Device muss dafür u.A. des MSwitch Device selber sein).&lt;br /&gt;
&lt;br /&gt;
Es wird hierbei KEIN echtes Event generiert welches das System beeinflusst, sondern ausschließlich ein MSwitch-Interner Befehl umgesetzt!&lt;br /&gt;
&lt;br /&gt;
Bei dem Einsatz dieser Möglichkeit sollte das Attribut &#039;MSwitch_Safemode&#039; UNBEDINGT aktiviert sein, da &#039;Experimente&#039; hier schnell in einer Endlosschleife enden können, die nur durch ein Reboot unterbrochen werden kann. &lt;br /&gt;
&lt;br /&gt;
Ggf. werde ich hier sogar eine entsprechende Änderung vornehmen, dass dieser Befehl nur zur Verfügung steht, wenn Safemode aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
=== get-Befehle ===&lt;br /&gt;
==== get show_timer [&amp;lt;show&amp;gt;&amp;lt;delete&amp;gt;] ====&lt;br /&gt;
;Show&lt;br /&gt;
:Zeigt alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren.&lt;br /&gt;
;Delete&lt;br /&gt;
:Löscht alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren. Schaltbefehle basierend auf rein zeitabhängigen Angaben werden neu berechnet und gesetzt.&lt;br /&gt;
&lt;br /&gt;
==== get restore_MSwitch_data [&amp;lt;this_device&amp;gt;&amp;lt;all_devices&amp;gt;] ====&lt;br /&gt;
;this_device&lt;br /&gt;
:Stellt die Daten des Devices aus der Backupdatei wieder her, sofern diese in der Backupdatei gefunden werden (gesucht wird hier nach dem Namen des Devices).&lt;br /&gt;
;all_devices&lt;br /&gt;
:Stellt die Daten aller MSwitch Devices wieder her, sofern diese in der Backupdatei vorhanden sind. Diese Aktion kann einige Zeit in Anspruch nehmen und wird daher im Hintergrund (nonblocking) ausgeführt. Nach Beendigung erfolgt eine Benachrichtigung.&lt;br /&gt;
&lt;br /&gt;
Die Devices sind nach einem Restore funktionsfähig. Empfohlen wird ein Neustart von FHEM.&lt;br /&gt;
&lt;br /&gt;
==== get_config ==== &lt;br /&gt;
Zeigt die Konfigurationsdatei des MSwitchdevices an; diese kann in dem Fenster editiert werden. Das sollte nur von erfahrenen Usern getan werden! Im Normalfall sollte das Device nur über die Weboberfläche konfiguriert werden und eine falsche Konfiguration kann hier zu einem FHEM Absturz führen.&lt;br /&gt;
&lt;br /&gt;
==== get_support_info ==== &lt;br /&gt;
Öffnet ein Fenster mit einer formatierten Ansicht aller Einstellungen des Devices. Bei Supportanfragen sollte dieses immer mit geposted werden.&lt;br /&gt;
&lt;br /&gt;
==== get_MSwitch_preconf ====&lt;br /&gt;
Lädt vorkonfigurierte MSwitch-Devices. Diese Option ist nur dann vorhanden, wenn das Aktualisieren dieser vorkonfigurierten Devices im FHEM Update aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
Diese kann durch ein einmaliges Update erfolgen mit:&lt;br /&gt;
:&amp;lt;code&amp;gt;update all https://raw.githubusercontent.com/Byte009/MSwitch_Addons/master/controls_mswitchaddons.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Webinterface ==&lt;br /&gt;
MSwitch wird im Wesentlichen über das Webinterface eingerichtet. Wählt man das folgende Attribut&lt;br /&gt;
:&amp;lt;code&amp;gt;attr &amp;lt;name&amp;gt; MSwitch_Help 1&amp;lt;/code&amp;gt;&lt;br /&gt;
so wird im Modul selber eine sehr umfangreiche Hilfe angezeigt. Über das gesamte Webinterface hinweg erscheinen kleine Fragezeichen, die man anklicken kann und die beschreiben, was in dem jeweiligen Textfeld sinnvollerweise einzugeben ist bzw. was das Modul an dieser Stelle erwartet.&lt;br /&gt;
&lt;br /&gt;
Das Webinterface besteht aus vier Teilen. Änderungen in jedem Abschnitt müssen in dem jeweiligen Teil bestätigt werden und auch nur diese werden gespeichert. Bevor ein weiterer Teil bearbeitet wird, sollten Änderungen gespeichert werden, sie gehen sonst verloren.&lt;br /&gt;
&lt;br /&gt;
=== Trigger device/time ===&lt;br /&gt;
==== Trigger Device ====&lt;br /&gt;
In diesem Feld wird das Device ausgewählt, dessen Events eine Aktion auslösen sollen. Dazu werden alle verfügbaren Devices in einem Dropdownfeld angeboten.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es eine Auswahl &#039;GLOBAL&#039;, wenn das Attribut &#039;MSwitch_Expert&#039; gesetzt ist. Bei Auswahl dieser Option werden &#039;&#039;&#039;alle&#039;&#039;&#039; von FHEM generierten Events durch das MSwitch Device weiterverarbeitet, eine weitere Begrenzung der aktivierenden Events kann (und sollte) dann in einem folgenden Eingabefeld erfolgen, um die Systemlast zu reduzieren.&lt;br /&gt;
&lt;br /&gt;
==== Trigger Device Global Whitelist ====&lt;br /&gt;
Dieses Feld ist nur verfügbar, wenn als Trigger &#039;GLOBAL&#039; gewählt wurde.&lt;br /&gt;
&lt;br /&gt;
Hier kann die Liste eingehender Events weiter eingeschränkt werden. Es handelt sich um eine Whitelist, d.h., wenn es keine Einträge gibt, werden Events aller Devices verarbeitet. Sobald ein oder mehrere Einträge gemacht werden, werden nur noch Events der hier benannten Devices verarbeitet. Als Angabe können hier Devices benannt werden oder ganze DeviceTypen (z.B. TYPE=FS20). Mehrere Angaben sind durch Komma zu trennen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:MSwitchWebinterface1.png|400px|thumb|right|Webinterface, oben]]&lt;br /&gt;
Im gezeigten Beispiel wurde GLOBAL gewählt, weil nicht ein einzelnes Device, sondern eine Kombination aus zwei Geräten auslösen soll. Es werden also alle Ereignisse betrachtet, wobei die Whitelist dann auf die Devices Schlafzimmer (ein Temperaturmessgerät) und Schlafzimmerfenster (ein [[HM-Sec-SCo Tür-Fensterkontakt, optisch|optischer Kontakt]]) einschränkt. &lt;br /&gt;
&lt;br /&gt;
==== Trigger time ==== &lt;br /&gt;
Es besteht die Möglichkeit, das Modul (neben den Events) zu festen Zeiten auszulösen. Dann wären in die leer stehenden Zeilen bei &amp;quot;at&amp;quot; entsprechende Termine einzutragen. Zeitangaben erfolgen durch [STUNDEN:MINUTEN|TAGE], wobei die Tage von 1-7 gezählt werden (1 steht für Montag, 7 für Sonntag usw.). &lt;br /&gt;
Mehrere Zeitvorgaben können direkt aneinandergereiht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [17:00|1][18:30|23] den Trigger montags um 17 Uhr auslösen und dienstags sowie mittwochs um 18:30 Uhr.&lt;br /&gt;
Bei [00:10*20:00-21:00] würde der Schaltbefehl von 21 Uhr bis 21 Uhr alle 10 Minuten ausgeführt. Bei [?20:00-21:00] würde der Schaltbefehl zu einem zufälligen Zeitpunkt zwischen 20 und 21 Uhr ausgeführt.  [20:00|$we] bedeutet, dass nur am Wochenende um 20:00 geschaltet wird.&lt;br /&gt;
&lt;br /&gt;
==== Trigger conditions ====&lt;br /&gt;
Hier kann die Angabe von Bedingungen erfolgen, die zusätzlich zu dem triggernden Device erfüllt sein müssen.&lt;br /&gt;
Diese Bedingungen sind eng an DOIF-Syntax angelehnt. Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich.&lt;br /&gt;
&lt;br /&gt;
Wird in diesem Feld keine Angabe gemacht, so erfolgt der Schaltvorgang nur durch das triggernde Device ohne weitere Bedingungen.&lt;br /&gt;
&lt;br /&gt;
;Zeitabhängigkeit&lt;br /&gt;
:[19:10-23:00] - Trigger des Devices erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
;Readingabhängige Trigger&lt;br /&gt;
:[Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Trigger des Device erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
:Werden Readings mit Strings abgefragt (on,off,etc.), ist statt des Gleichheitszeichens &amp;quot;=&amp;quot; der Operator &amp;quot;eq&amp;quot; zu nutzen, der String muss in Anführungszeichen &amp;quot;&amp;quot; gesetzt werden.&lt;br /&gt;
;mehrere Beispiele&lt;br /&gt;
:[19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
:[19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
:[10:00-11:00|13] - schaltet Montag und Mittwoch zwischen 10 Uhr und 11 Uhr.&lt;br /&gt;
:[{ sunset() }-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
:{ !$we } löst den Schaltvorgang nur Werktagen an aus.&lt;br /&gt;
:{ $we } löst den Schaltvorgang nur an Wochenenden, Feiertagen aus.&lt;br /&gt;
&lt;br /&gt;
Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (beispielsweise würde dann am Mittwoch noch der Schaltvorgang erfolgen, obwohl als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
Bedingungen in diesem Feld gelten nur für auslösende Trigger eines Devices und haben keinen Einfluss auf zeitgesteuerte Auslöser.&lt;br /&gt;
&lt;br /&gt;
=== Trigger details ===&lt;br /&gt;
[[Datei:MSwitchWebinterface2.png|600px|thumb|right|Webinterface, Mitte]]&lt;br /&gt;
Während im obigen Feld das Device ausgewählt  werden konnte, wird hier das Ereignis festgelegt. Das Eingabefeld besteht aus mehreren Einzelfeldern.&lt;br /&gt;
&lt;br /&gt;
Im abgebildeten Fall wird cmd1 ausgelöst, wenn der Zustand des Schlafzimmerfenster-Sensors meldet, dass das Fenster offen ist. Cmd2 wird ausgelöst, wenn die Temperatur des Schlafzimmersensors unter einen bestimmten Wert fallen wird.&lt;br /&gt;
&lt;br /&gt;
==== execute &#039;cmd1/cmd2&#039;  ====&lt;br /&gt;
Hier kann  aus einer vorbelegten Dropdownliste ausgewählt werden, welches ankommende Event den entsprechenden Befehlszweig auslösen soll. In dieser Liste werden bei entsprechender Einstellung alle ankommenden Events eines vorher definierten Devices gespeichert. In einem weiteren Feld (siehe unten) können Events manuell zugefügt werden.&lt;br /&gt;
&lt;br /&gt;
==== Save incomming events ====&lt;br /&gt;
Bei Aktivierung dieser Option werden alle ankommenden Events des oben definierten Devices (oder Global) gespeichert und in entsprechenden Dropdownlisten angeboten.&lt;br /&gt;
&lt;br /&gt;
Da hier doch erhebliche Datenmengen anfallen können (je nach Device) wird empfohlen, diese Option nach der Konfiguration des Devices zu deaktivieren.&lt;br /&gt;
&lt;br /&gt;
==== add event ====&lt;br /&gt;
Hier besteht die Möglichkeit, unabhängig von der Option, ankommende Events automatisch zu speichern. Manuell Events anzulegen, die in den Dropdownliste zur Auswahl angeboten werden, ohne das entsprechendes Event erst vom Device geliefert werden muss.&lt;br /&gt;
&lt;br /&gt;
Es können mehrere Events gleichzeitig eingegeben werden, eine Trennung erfolgt durch &amp;quot; , &amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Hier ist zu unterscheiden, ob das gewählte triggernde Device ein einfaches Device ist oder ob der Trigger &#039;GLOBAL&#039; ist.&lt;br /&gt;
Bei triggernden Devices können Events in folgendem Formaten zugefügt werden:&lt;br /&gt;
&lt;br /&gt;
- *                                                    - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:wert   (z.b. state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:*      (z.b. state:* )                       - Aktion erfolgt auf die Events &amp;quot;state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:(wert1/wert2/wert3) (z.b. state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;state:left&amp;quot; oder &amp;quot;state:right&amp;quot; etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Falls auf &#039;GLOBALE&#039; Events getriggert wird, muss das auslösende Device vorangestellt werden:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
- *                                                           - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:wert   (z.b. device:state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;device:state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:*      (z.b. device:state:* )                       - Aktion erfolgt auf die Events &amp;quot;device:state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:(wert1/wert2/wert3) (z.b. device:state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;device:state:left&amp;quot; oder &amp;quot;devicestate:right&amp;quot; etc.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Device kann auch hier gegen &amp;quot;*&amp;quot; ersetzt werden (*:state:on). In diesem Fall erfolgt eine Aktion auf alle Events die z.B. &amp;quot;state:on&amp;quot; enthalten, egal welches Device triggert.&lt;br /&gt;
&lt;br /&gt;
==== test event ====&lt;br /&gt;
Dieses Feld wird angeboten, wenn entsprechende vom Triggerdevice gelieferte Events gespeichert wurden.&lt;br /&gt;
&lt;br /&gt;
Durch Auslösen dieser Funktion wird das Event simuliert und entsprechende definierte Aktionen ausgelöst. Diese Funktion dient ausschließlich zum Testen der eingestellten Konfiguration. Alle entsprechenden Befehle werden ausgeführt, als würde das Event real eintreffen.&lt;br /&gt;
&lt;br /&gt;
==== apply filter to saved events ====&lt;br /&gt;
Beschreibung folgt&lt;br /&gt;
&lt;br /&gt;
==== clear saved event ====&lt;br /&gt;
Es werden alle gespeicherten Events gelöscht.&lt;br /&gt;
&lt;br /&gt;
Ausnahme: Events, die als Trigger eingestellt sind, bleiben erhalten.&lt;br /&gt;
&lt;br /&gt;
=== Affected devices ===&lt;br /&gt;
[[Datei:MSwitch_Screen_5.png|mini|rechts|affected devices]]&lt;br /&gt;
Dieser Abschnitt beinhaltet die Auswahl der Devices, die auf ein Event reagieren sollen.&lt;br /&gt;
&lt;br /&gt;
In dem Auswahlfeld werden alle Devices angeboten, die eines der folgenden Kriterien erfüllen:&lt;br /&gt;
# Die Abfrage &amp;quot;set Device ?&amp;quot; liefert einen Befehlssatz&lt;br /&gt;
# Das Attribut &#039;webcmd&#039; des Devices enthält Einträge&lt;br /&gt;
# Das Attribut &#039;MSwitch_Activate_MSwitchcmds&#039; ist aktiviert und das Attribut &#039;MSwitchcmds&#039; des betreffenden Devices enthält einen Befehlssatz&lt;br /&gt;
&lt;br /&gt;
Einzige Ausnahme ist der erste Listeneintrag &#039;FreeCMD&#039;. Die Auswahl dieses Eintrages bietet später die Möglichkeit Befehle auszuführen, die nicht an ein Device gebunden sind. Der Code in einem FreeCmd kann entweder reiner FHEM-Code sein ( set device on ) oder reiner Perl-Code. Wenn es sich um reinen Perl-Code handelt, ist dieser in geschweifte Klammen zu setzen { Perl-Code }.&lt;br /&gt;
&lt;br /&gt;
=== Device actions ===&lt;br /&gt;
[[Datei:Webinterface3.png|mini|rechts|device_actions]]&lt;br /&gt;
Hier stellt man die auszuführenden Aktionen der eingestellten Devices ein. Im ersten Abschnitt oben befindet sich ein FreeCmd, mit dem beliebige Kommandos eingetragen werden können. Im abgebildeten Beispiel ist dies sogar selbst definierter Perl-Code (die Funktion DebianMail sendet eine Mail). &lt;br /&gt;
&lt;br /&gt;
==== MSwitch cmd1/cmd2:  ====&lt;br /&gt;
Man wählt den Befehl aus dem betreffenden Device aus. Bei freien Textfeldern (wie im Fall des FreeCmd) wird der Befehl eingegeben.&lt;br /&gt;
&lt;br /&gt;
Es werden alle verfügbaren Befehle des Devices zur Auswahl angeboten. Je nach Attribut-Einstellungen werden Einträge aus entsprechenden &#039;webcmds&amp;quot; oder &#039;MSwitchcmds&#039; einbezogen. In Abhängigkeit des Befehls stehen unter Umständen weitere Felder oder Widgets zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
05.04.2018 NEU: Auswahlfeld &#039;MSwitchtoggle&#039; -&amp;gt; Beschreibung wird noch ergänzt !&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 condition  ====&lt;br /&gt;
Mit diesem Feld kann die Ausführung des Befehls von weiteren Bedingungen abhängig gemacht werden. Bei der Abfrage von Readings nach Strings (on, off, etc.) ist statt &amp;quot;=&amp;quot; &amp;quot;eq&amp;quot; zu nutzen und der String muss in &amp;quot;x&amp;quot; gesetzt werden. Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
#Zeitabhängiges schalten: [19:10-23:00] - Schaltbefehl erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
#Readingabhängiges schalten [Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Schaltbefehl erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
&lt;br /&gt;
Soll nur an bestimmten Wochentagen geschaltet werden, muss eine Zeitangabe gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [10:00-11:00|13] den Schaltvorgang nur Montag und Mittwoch zwischen 10 Uhr und 11 Uhr auslösen. Hierbei zählen die Wochentage von 1-7 für Montag-Sonntag.&lt;br /&gt;
&lt;br /&gt;
Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich:&lt;br /&gt;
* [19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
* [19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
* [{sunset()}-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
* { !$we } löst den Schaltvorgang nur Werktagen aus&lt;br /&gt;
* { $we } löst den Schaltvorgang nur Wochenenden, Feiertagen aus&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung:&#039;&#039;&#039; Bei Anwendung der geschweiften Klammern zur Einleitung eines Perl Ausdrucks ist unbedingt auf die Leerzeichen hinter und vor der Klammer zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (zum Beispiel würde auch am Mittwoch noch der Schaltvorgang erfolgen, wenn als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
; $EVENT:&lt;br /&gt;
: Die Variable EVENT enthält den auslösenden Trigger, d.h. es kann eine Reaktion in direkter Abhängigkeit zum auslösenden Trigger erfolgen.&lt;br /&gt;
&lt;br /&gt;
[$EVENT] eq &amp;quot;state:on&amp;quot; würde den Kommandozweig nur dann ausführen, wenn der auslösende Trigger &amp;quot;state:on&amp;quot; war. Wichtig ist dieses, wenn bei den Triggerdetails nicht schon auf ein bestimmtes Event getriggert wird, sondern hier durch die Nutzung eines Wildcards (*) auf alle Events getriggert wird, oder auf alle Events eines Readings z.B. (state:*).&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 delay  ====&lt;br /&gt;
Ein Eintrag in diesem Feld führt zur verzögerten Ausführung des Befehls nach Eintreffen des Events. Dabei kann der Befehl ohne weitere Prüfung der Bedingung ausgelöst werden. Es ist aber auch möglich, dass die Bedingung bei Ausführung erneut geprüft wird. Die Zeitangabe muss im Format hh:mm:ss vorliegen.&lt;br /&gt;
&lt;br /&gt;
Statt einer unmittelbaren Zeitangabe kann hier auch ein Verweis auf ein Reading eines Devices erfolgen :&amp;lt;br&amp;gt;&lt;br /&gt;
[NAME.reading] des Devices -&amp;gt;z.B. [dummy.state]&lt;br /&gt;
&lt;br /&gt;
==== add action  ====&lt;br /&gt;
Mit diesem Button kann ein weiteres Eingabefeld für das entsprechende Device angelegt werden, um z.B. einen weiteren Befehl (ggf.) zeitverzögert auszuführen.&lt;br /&gt;
&lt;br /&gt;
==== delete this action  ====&lt;br /&gt;
Mit diesem Button wird der entsprechende Befehl für das Device gelöscht.&lt;br /&gt;
&lt;br /&gt;
==== check condition  ====&lt;br /&gt;
[[Datei:MSwitch_Screen_7.png|mini|rechts|check]]&lt;br /&gt;
Die angegebenen &#039;conditions&#039; werden in Zusammenhang mit ggf. ausgewählten Devices auf Syntax und Ergebnis geprüft. Es erfolgt eine Ausgabe des Prüfungsergebnisses.&lt;br /&gt;
&lt;br /&gt;
==== Repeat und Repeatdelay ====&lt;br /&gt;
Man kann mehrfache Wiederholungen erzwingen. Repeat gibt dabei an, wie oft das Kommando wiederholt wird (Anzahl). Repeatdelay gibt an, wie viel Sekunden zwischen einzelnen Wiederholungen liegen sollen.&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Folgende Attribute stehen zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Debug (0:1:2:3:4) ===&lt;br /&gt;
0 - Abgeschaltet&amp;lt;br&amp;gt;&lt;br /&gt;
1 - Schaltet Felder zum testen der Conditionstrings etc. an&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Alle ausgehenden Befehle werden nur simuliert und nicht ausgeführt. Es erfolgt eine Protokollierung in einer separaten Datei . Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Es erfolgt eine Protokollierung in einer separaten Datei . Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
4 - erweiterte Debugfunktion (nur für Entwicklung - wechselnde Funktion )&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Expert (0:1) ===&lt;br /&gt;
In der Liste der möglichen Trigger erscheint das Selectfeld &#039;GLOBAL&#039;. Dieses ermöglicht das Setzen eines Triggers auf alle Events und damit nicht nur auf einzelne Devices. In einem weiteren Feld kann eine weitere Selektion der triggernden Events erfolgen.&lt;br /&gt;
&lt;br /&gt;
Es stehen weitere Felder &#039;Repeats&#039; und &#039;Repeatdelay in sec&#039; zur Verfügung. Eine hier getätigte Einstellung bewirkt X-fache Wiederholung von gesetzten Befehlen im Abstand der gesetzten Sekunden.&lt;br /&gt;
&lt;br /&gt;
Weiterhin kann über das Auswahlfeld &#039;priotity&#039; bei jedem &#039;affectes device&#039; die Reihenfolge beim abarbeiten der Befehle beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequenz &amp;lt;Suchmuster&amp;gt; ===&lt;br /&gt;
In diesem Attribut können ein oder mehrere Suchmuster angegeben werden ,die eine Schaltsequenz darstellen und vom Device erkannt werden.&lt;br /&gt;
&lt;br /&gt;
Die Angabe muss folgende Syntax haben:&lt;br /&gt;
:&amp;lt;code&amp;gt;Device1:reading1:event1 Device1:reading1:event1-2 Device1:reading1:event1-3/..../....&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mehrere Suchmuster müssen durch &amp;quot;/&amp;quot; getrennt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
:&amp;lt;code&amp;gt;Dummy:state:on Dummy:state:off Dummy:state:on&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erkennt das Device dieses Suchmuster in den Schaltvorgängen des Devices (Dummy), wird das Reading &amp;quot;SEQUENCE&amp;quot; auf &amp;quot;match&amp;quot; gesetzt, das Reading &amp;quot;SEQUENCE_NUMBER&amp;quot; auf die Nummer der gefundenen Sequenz, wenn es mehrere Suchmuster gibt. Beide Readings können in den &amp;quot;Conditions&amp;quot; eines Schaltbefehles abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequence_time &amp;lt;Zeit in Sekunden&amp;gt; ===&lt;br /&gt;
Beinhaltet die Zeit in Sekunden, die es dauern darf, um eine Sequenz vollständig auszuführen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Extensions (0:1) ===&lt;br /&gt;
Es wird eine zusätzliche Schaltoption &#039;MSwitchToggle&#039; in den Geräten angeboten. Diese kann genutzt werden, wenn zuschaltende Geräte eine Togglefunktion nicht von Haus aus anbieten.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe muss in folgendem Format gemacht werden:&lt;br /&gt;
:&amp;lt;code&amp;gt;on/off/state/suchmuster1/suchmuster2&amp;lt;/code&amp;gt;, wobei die letzten drei Angaben optional sind.&lt;br /&gt;
&lt;br /&gt;
Funktion: Bei Ausführung des Befehls wird das Gerät &#039;on&#039; oder &#039;off&#039; geschaltet (on/off), Voraussetzung ist, dass der &#039;state&#039; dieses Gerätes auch den &#039;state on&#039; oder &#039;off&#039; annimmt. Sollte dieses nicht der Fall sein, so kann mit dem Feld &#039;state&#039; angegeben werden, in welchem Reading der aktuelle Status vorkommt und wie dieser lautet (suchmuster1/suchmuster2). Dieses &#039;state&#039; kann mehrere Angaben enthalten, das Vorkommen der Suchmuster ist aber Voraussetzung.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Delete_Delays (0:1) ===&lt;br /&gt;
Bewirkt das Löschen aller anstehende Timer (Delays) bei dem Auftreten eines erneuten, passenden Events. Bei der Option &#039;0&#039; bleiben bereits gesetzte Delays aus einem vorherigen, getriggertem Event erhalten und werden ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1)&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Devicecmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz liefern (bei Abfrage set DEVICE ?).&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Webcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut Webcmd hinterlegt haben. Die in Webcmd hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten.&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Activate_MSwitchcmds (0:1) ===&lt;br /&gt;
Fügt jedem vorhandenen Device as Attribut &#039;MSwitchcmd&#039; hinzu.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_MSwitchcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut MSwitchcmds hinterlegt haben. Die in MSwitchcmds hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten. Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr Angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Lock_Quickedit (0:1) ===&lt;br /&gt;
Voreinstellung für die Auswahlliste &#039;Affected Devices&#039;. Bei der Option (1) ist diese voreingestellt gesperrt und kann nur über einen zusätzlichen Button geändert werden. Da es sich hier um ein Feld mit der Möglichkeit einer Mehrfacheingabe handelt handelt ist die Voreinstellung 1, um versehentliche nicht gewünschte Änderungen zu vermeiden (Auswahl einer Option ohne &#039;Strg&#039; bewirkt das löschen aller bereits gesetzten Optionen).&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay (0:10:20:30:60) ===&lt;br /&gt;
Diese Einstellung beeinflusst den Start von MSwitch nach einem FHEM Start. MSwitch ignoriert für die angegebene Zeit in Sekunden alle eingehenden Events um u.a. Startverzögerungen zu vermeiden. Bei nicht gesetztem Attribut gilt hier eine Zeit von 30 Sekunden. Diese sollte auch nur in Ausnahmefällen bzw. bei besonderem Bedarf geändert werden.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (30).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Ignore_Types ===&lt;br /&gt;
Beinhaltet eine Liste von Device&#039;&#039;typen&#039;&#039;, die in den Auswahllisten &#039;&#039;nicht&#039;&#039; dargestellt werden. Hier ist es sinnvoll, Devicetypen einzutragen, die in aller Regel nicht geschaltet werden oder nicht geschaltet werden können, um die Auswahllisten übersichtlicher zu halten. Einzelne Devicetypen sind durch Leerzeichen zu trennen.&lt;br /&gt;
&lt;br /&gt;
Voreinstellung: notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe kann hier in 2 Arten getätigt werden:&lt;br /&gt;
# eine Liste von devicetypen.&lt;br /&gt;
# Angabe einer devspec z.B. &amp;quot;TYPE=watchdog&amp;quot;. Hier ist zu beachten, dass in diesem Fall alle Geräte in die Ignoreliste einbezogen werden, die NICHT der devspec entsprechen. Weiterhin muss die devspec in Anführungszeichen gesetzt werden!&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Trigger_Filter ===&lt;br /&gt;
Beinhaltet eine Liste von Events, die bei eingehenden Events unberücksichtigt bleiben. Diese werde dann auch nicht gespeichert.&lt;br /&gt;
&lt;br /&gt;
Hier kann mit Wildcards (*) gearbeitet werden. Einzelne Events sind durch Komma &#039;,&#039; zu trennen.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (keine).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Wait (sec)===&lt;br /&gt;
Bei gesetztem Attribut (Zeit in Sekunden) nimmt Das MSwitch Device für den eingestellten Zeitraum keine Befehle mehr entgegen und ignoriert eingehende Events&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Event_Id_Distributor ===&lt;br /&gt;
Dieses Attribut hat nur dann eine Funktion, wenn auch das Attribut &#039;MSwitchExpert&#039; auf &#039;1&#039; gesetzt ist.&lt;br /&gt;
Hier können verschiedene auslösende Events auf Aktionen mit angegebenen IDs umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Sollte bei den &#039;trigger details :&#039; in einem Zweig ( cmd1 ) z.B. auf mehrere Events getriggert werden ( regex z.B. state:(on|off) ) so werden für beide Events jeweils der Zweig &#039;cmd1&#039; - alle  Aktionen ohneID - ausgeführt. Durch entsprechende Einträge kann für entsprechende Events auf eine Aktion umgeleitet werden, für die eine ID definiert ist. Die Syntax lautet:&lt;br /&gt;
:&amp;lt;code&amp;gt;state:on=&amp;gt;cmd1 ID 1,2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden bei auslösendem Event &#039;state:on&#039; nur die Aktionen aus cmd1 mit den IDs 1 und 2 ausgeführt. Mehrere Angaben sind durch new Line zu trennen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Selftrigger_always (0,1)===&lt;br /&gt;
(dieses Attribut steht ab Modulversion 2.5 zur Verfügung)&lt;br /&gt;
&lt;br /&gt;
Die Aktivierung dieses Attributes (1) bewirkt, dass alle SET Aktionen des Devices einen (internen) Event auslösen, auf die das Device selber reagiert. Diese Option kann zusätzlich zu einem vorhandenen Trigger aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Diese Events sind lediglich Deviceintern, d.h es werden keine Modulübergreifenden Events ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Auftretende und auswertbare interne Events haben immer folgendes Format und können darüber ausgewertet werden.&lt;br /&gt;
&lt;br /&gt;
MSwitch_Self:aktion:wert &lt;br /&gt;
MSwitch_Self:pct:100&lt;br /&gt;
&lt;br /&gt;
Es werden nur interne Events für set-Aktionen ausgelöst, die im Attribut setlist hinterlegt sind.&lt;br /&gt;
&lt;br /&gt;
Als weitere Besonderheit unterliegen diese internen Events nicht dem &#039;wait&#039; Befehl/Attribut&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Mode (Notify,Full,Toggle,Dummy)===&lt;br /&gt;
Schaltet das Modul zwischen verschiedenen Modi um, mit entsprechend angepasster Weboberfläche.&lt;br /&gt;
&lt;br /&gt;
==== Notify ====&lt;br /&gt;
Das Device kann nicht manuell umgeschaltet werden, es gibt nur zwei ausführbare Zweige (execute &#039;cmd1&#039; commands und execute &#039;cmd2&#039; commands). Der Status des Devices wird nicht als &#039;on&#039; oder &#039;off&#039; angezeigt, sondern lediglich als &#039;active&#039;&lt;br /&gt;
&lt;br /&gt;
Dieser Mode ist am ehesten mit einem Notify zu Vergleichen.&lt;br /&gt;
==== Full ====&lt;br /&gt;
Es stehen alle Funktionen zur Verfügung.&lt;br /&gt;
==== Toggle ====&lt;br /&gt;
Sehr vereinfachter Mode. Es stehen keine verschiedenen Zweige zur Verfügung. Hier ist das Device manuell schaltbar und wird bei jedem definierten Event &#039;Umgeschaltet&#039;, entsprechend definierte Befehle für &#039;cmd1&#039; oder &#039;cmd2&#039; werden ausgeführt.&lt;br /&gt;
==== Dummy====&lt;br /&gt;
ACHTUNG: Funktionsänderung mit V2.61&lt;br /&gt;
&lt;br /&gt;
Der Mode &#039;Dummy&#039; ist ein eingeschränkter Modus. &lt;br /&gt;
Dieser bietet die Funktionalität eines Dummys kombiniert mit der Funktionalität eines Notifys und kann somit die gerne genutzte Kombination Dummy-Notify gegen ein Device ersetzen.&lt;br /&gt;
&lt;br /&gt;
Achtung: Devices die einmal in dem Modus &#039;Dummy&#039; gesetzt wurden können nicht wieder in einen anderen Mode geschaltet werden ! &lt;br /&gt;
&lt;br /&gt;
Der Dummy-Mode kann nur in einem neu angelegtem, leeren MSwitch aktiviert werden. Sobald ein angelegtes MSwitch einmal verändert wurde (modify trigger etc.) ist ein Umschalten nicht mehr möglich und die Option nicht mehr verfügbar.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Condition_Time (0,1)===&lt;br /&gt;
In der Grundeinstellung (0) werden für das zeitgesteuerte Schalten keine definierten Conditionen im Feld &#039;Trigger condition&#039; überprüft, sondern die Schaltbefehle werden in jedem Fall ausgeführt. Mit der Einstellung (1) wird diese Überprüfung auch für zeitgesteuerte Befehle zugeschaltet.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Time (HH:MM:SS-HH:MM:SS)===&lt;br /&gt;
Bei Aktivierung wird vor jedem Ausführen eines verzögerten Befehls ( Delay ) eine Zufallszeit generiert, die im Rahme der hier angegebenen Zeitspanne liegt. Auf diese Zufallszahl kann in den Delays zugegriffen werden, durch die Angabe &#039;[random]&#039; statt einer direkten Zeitangabe. Bei nicht gesetztem Attribut ergibt die Angabe von &#039; [random] &#039; hier immer &#039;00:00:00&#039;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Number ===&lt;br /&gt;
Bei Aktivierung dieses Attributes (der Inhalt kann einen beliebige Zahl sein) werden vom Device 2 Readings angelegt (Device:RandomNr) und (Device:RandomNr1). RandomNr wird vor jedem Ausführen eines Befehls aktualisiert und neu generiert, d.h wenn ein MSwitch Device mehrere Geräte schaltet, wird (auch in einem Durchgang) vor jedem Befehl dieses Reading neu gesetzt. RandomNr1 wird lediglich bei Ausführung des MSwitch Devices einmal neu gesetzt, d.h. nicht vor jedem Befehl der ausgeführt wird.&lt;br /&gt;
Die Readings werden mit einer Zufallszahl zwischen 0 und dem hier eingestellten Wert gesetzt.&lt;br /&gt;
&lt;br /&gt;
Auf diese Readings kann in jeder Condition mit z.B. &#039;[$NAME:ReadingNr1] = 1&#039; zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
D.h., das in der Condition angegebene Reading ( [$NAME:ReadingNr1] ) muss in diesem Fall den Wert 1 angenommen haben, ansonsten wird der Befehl nicht ausgeführt. &lt;br /&gt;
Der Befehl wird somit nur mit einer Wahrscheinlichkeit von 1 zu ( gesetzter Wert im Attr. ) ausgeführt.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Reset_EVT_CMD1(2)_COUNT ===&lt;br /&gt;
Bei Aktivierung dieses Attributes steht in den Readings das Reading &#039;EVT_CMD1_COUNT&#039; bzw. &#039;EVT_CMD2_COUNT&#039; zur Verfügung. Dieses kann in den Conditions genutzt werden, um z.B. nur bei jedem x-ten Eintreffen eines auslösenden Events einen Befehl auszuführen. Bei jedem Eintreffen eines gültigen Events werden die Zähler um 1 erhöht (für den jeweiligen Zweig). &lt;br /&gt;
Ist hier der Wert &#039;0&#039; eingetragen, wird der Zähler fortlaufend (endlos) erhöht. Wird ein Wert größer 0 eingetragen, wird der Zähler mit Erreichen dieses Wertes automatisch wieder auf Null gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit Löschen dieses Attributes werden die entsprechenden Readings ebenfalls gelöscht.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Safemode (0:1)===&lt;br /&gt;
Bietet einen (gewissen) Schutz vor falschen Konfigurationen und somit entstehenden Endlosschleifen.&lt;br /&gt;
Bei aktiviertem Attribut (1) erkennt das Modul Endlosschleifen eines Devices und beendet diese.&lt;br /&gt;
&lt;br /&gt;
In diesem Fall erfolgt ein Logeintrag und das Device wird per Attribut auf &#039;Disabled&#039; gesetzt.&lt;br /&gt;
Es wird ein letztes Event generiert, auf das reagiert werden kann:&lt;br /&gt;
:&amp;lt;code&amp;gt;2018-05-31 09:39:21 MSwitch &amp;lt;NAME&amp;gt; Safemode: on&amp;lt;/code&amp;gt;&lt;br /&gt;
Im Webinterface erfolgt bei betroffenem Device ein entsprechender Hinweis.&lt;br /&gt;
&lt;br /&gt;
In der Grundkonfiguration ist dieses Attribut nicht gesetzt, es empfiehlt sich aber, bei neuen (komplizierten) Devices, dieses - zumindest anfänglich - zu aktivieren.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Read_Log(0:1)===&lt;br /&gt;
Ermöglicht den Zugriff auf das Logfile als Trigger.&lt;br /&gt;
&lt;br /&gt;
Hier gibt es mehrere Konfigurationsmöglichkeiten:&lt;br /&gt;
* Bei aktiviertem Attribut enthält die Auswahl des Triggerdevices die Option &#039;LOGFILE&#039;. Bei dieser Auswahl werde alle Logeinträge erkannt und in ein internes Event umgewandelt, auf das regiert werden kann.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl &#039;GLOBAL&#039; im &#039;Trigger_Device&#039; wird auf ALLE Events und alle Logeinträge reagiert.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl eines bestimmten Devices im &#039;Trigger_Device&#039; wird auf alle Events  und auf alle Logeinträge des gewählten Devices reagiert. Hier ist zu beachten, dass FHEM mir keine Möglichkeit bietet, wirklich herauszufinden, welches Device denn nun einen Logeintrag generiert hat. D.h., dieses wird vom Vorhandensein des Namens im Logeintrag abhängig gemacht und MSwitch reagiert nur dann auf einen Logeintrag, wenn der Name des Devices in diesem Eintrag vorhanden ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Help(0:1)===&lt;br /&gt;
Schaltet Hilfebuttons zu den einzelnen Eingabefeldern an oder aus.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Comments(0:1)===&lt;br /&gt;
Schaltet Kommentarfelder zu den einzelnen &#039;affected_devices an.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_generate_Events(0:1)===&lt;br /&gt;
Reduziert bei Einstellung &#039;1&#039; die vom MSwitch-Devices erzeugten Events auf ein absolutes Minimum. Insbesondere bei Verwendung von &#039;MSwitch_Read_Log&#039; zu empfehlen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay ===&lt;br /&gt;
Bestimmt die Verzögerungszeit des MSwitches nach FHEM-Start in Sekunden. In diesem Zeitraum reagiert das ??Event??(Red: ist hier &amp;quot;Device&amp;quot; gemeint?) nicht auf Events. Die Vorgabe ist hier zehn Sekunden. Diese wird auch dann angenommen, wenn das Attribut nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Inforoom ===&lt;br /&gt;
Mit diesem Attribut wird die Raumansicht eines mit dem Attribut bestimmten Raumes verändert. Dadurch sollen die wichtigsten Informationen aller MSwitch-Devices auf eine Seite dargestellt werden. Zur Nutzung sollten alle MSwitch-Devices (zusätzlich) in einen Raum sortiert werden und dieser Raum im Attribut eingestellt werden.&lt;br /&gt;
&lt;br /&gt;
Wichtig: Eine Änderung dieses Attributes bewirkt immer eine Änderung dieses Attributes in &#039;&#039;allen&#039;&#039; MSwitch devices: Es muss nur in einem Device gesetzt oder gelöscht werden um alle Devices zu erfassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
MSwitch_Screen_1.png|Raumansicht des Raumes MSwitch mit gesetztem Attribut &#039;MSwitch&#039;&lt;br /&gt;
MSwitch_Screen_2.png|Raumansicht des Raumes MSwitch ohne gesetztes Attribut&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es werden folgende Informationen bereitgestellt:&lt;br /&gt;
* Infobutton zeigt den im Device gespeicherten Textes des Attributes &#039;comment&#039;&lt;br /&gt;
* Device und Events, die das Device triggern&lt;br /&gt;
* Zeiten, zu denen verschiedene Zweige des Devices ausgeführt werden&lt;br /&gt;
* Devices, die durch das MSwitch Device geschaltet werden&lt;br /&gt;
* State des Devices&lt;br /&gt;
&lt;br /&gt;
== Integrierte Funktionen ==&lt;br /&gt;
&lt;br /&gt;
=== Average ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
=== Tendency ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[TEND&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;Mindestwert&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[TEND2:countdown] &amp;gt; 2&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Es wird jeweils der Durchschnitt von 2 Wertepaaren gebildet. In diesem Fall werden die letzten 4 Werte herangezogen.&amp;lt;br&amp;gt;&lt;br /&gt;
Paar 1 = Aktueller und letzter Wert, Paar 2 = Die 2 vorherigen Werte.&amp;lt;br&amp;gt;&lt;br /&gt;
Bei TEND3 werden die letzten 6 Werte zur Paarbildung genutzt.&lt;br /&gt;
&lt;br /&gt;
Mindestwert:&lt;br /&gt;
Der Wertunterschied zwischen den Wertepaaren, der minimal erreicht sein muss, um eine Tendenz zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Rechenzeichen (&amp;gt;&amp;lt;):&lt;br /&gt;
Dieses ist hier nicht als Rechenzeichen zu werten, sonder als Tendenz-Anzeige. ( &amp;lt; es wird nach fallender Tendenz gesucht / &amp;gt; sucht nach steigender Tendenz).&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolgt einmalig bei Erkennung der gesuchten Tendenz.&lt;br /&gt;
Danach erfolgt keine Schaltung mehr, solange bis eine Tendenz-Umkehr erfolgt ist.&lt;br /&gt;
Erst dann erfolgt wieder eine Schaltung bei erneuter Tendenz-Umkehr in gesuchte Richtung.&lt;br /&gt;
&lt;br /&gt;
=== Difference ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[DIFF&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;differenz&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[DIFF2:countdown] &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Gespeicherter Wert (in diesem Fall der vorletzte).&lt;br /&gt;
&lt;br /&gt;
Differenz:&lt;br /&gt;
Geforderter Differenz zwischen aktuellem und vorletztem Wert.&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolg wenn diese Bedingung &#039;wahr&#039; ist.&lt;br /&gt;
&lt;br /&gt;
Folgende Readings werden zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
DIFFERENCE (true/false) - Schaltbedingung erkannt ja/nein&lt;br /&gt;
&lt;br /&gt;
DIFFDIRECTION (up/down) - Richtung der erkannten Bedingung (steigend/fallend)&lt;br /&gt;
&lt;br /&gt;
=== Increase ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
== Tipps, Tricks, Kurzbeispiele ==&lt;br /&gt;
Wird stetig ergänzt .&lt;br /&gt;
&lt;br /&gt;
=== Blinken - Falls nicht im Device vorhanden ===&lt;br /&gt;
[[Datei:MSwitch MSwitchblink.png|center|704px]]&lt;br /&gt;
&amp;lt;br clear=all&amp;gt;&lt;br /&gt;
Lässt ein beliebiges Device 5 mal togglen, mit einem Intervall von 0.5 Sekunden (Blinkzeit somit 2,5 Sekunden)&amp;lt;br&amp;gt;&lt;br /&gt;
Die MSwitchtoggle-Funktion muss per ATTR aktiviert werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Die Repeatfunktion ist nur im Expertmode verfügbar, auch per ATTR einstellbar.&lt;br /&gt;
&lt;br /&gt;
=== Linearschalter ===&lt;br /&gt;
Umsetzung eines Linearschalters mit MSwitch.&lt;br /&gt;
&lt;br /&gt;
Eingang: Beliebiges Reading als numerischer Wert.&lt;br /&gt;
&lt;br /&gt;
Ausgang: Wird entsprechend Linear / oder umgekehrt Linear zum Eingang geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgend die Rawdefinition des MSwitchdevices und zweier Dummys (selbsterklärend)&lt;br /&gt;
&lt;br /&gt;
Alle Devices werden im Raum Lineartest angelegt, die Dummy müssen zuerst angelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod linearausgang dummy&lt;br /&gt;
attr linearausgang room Lineartest&lt;br /&gt;
attr linearausgang setList state:slider,0,1,100&lt;br /&gt;
attr linearausgang webCmd state&lt;br /&gt;
setstate linearausgang state 57&lt;br /&gt;
setstate linearausgang 2018-06-06 18:06:12 state state 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod lineareingang dummy&lt;br /&gt;
attr lineareingang room Lineartest&lt;br /&gt;
attr lineareingang setList state:slider,0,1,15000&lt;br /&gt;
attr lineareingang webCmd state&lt;br /&gt;
setstate lineareingang 6422&lt;br /&gt;
setstate lineareingang 2018-06-06 18:06:12 state 6422&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod Linearschalter MSwitch lineareingang  # linearausgang FreeCmd&lt;br /&gt;
attr Linearschalter MSwitch_Debug 0&lt;br /&gt;
attr Linearschalter MSwitch_Delete_Delays 1&lt;br /&gt;
attr Linearschalter MSwitch_Expert 0&lt;br /&gt;
attr Linearschalter MSwitch_Extensions 0&lt;br /&gt;
attr Linearschalter MSwitch_Help 0&lt;br /&gt;
attr Linearschalter MSwitch_Ignore_Types notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
attr Linearschalter MSwitch_Include_Devicecmds 1&lt;br /&gt;
attr Linearschalter MSwitch_Include_MSwitchcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Include_Webcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Inforoom MSwitch&lt;br /&gt;
attr Linearschalter MSwitch_Lock_Quickedit 1&lt;br /&gt;
attr Linearschalter MSwitch_Mode Notify&lt;br /&gt;
attr Linearschalter room Lineartest&lt;br /&gt;
&lt;br /&gt;
setstate Linearschalter active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:03:50 .Device_Affected FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:04:35 .Device_Affected_Details FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 );;my $emin=0;;my $emax=15000;;my $amin=100;;my $amax=0;;$eingang = $emin if $eingang &amp;lt; $emin;;$eingang = $emax if $eingang &amp;gt; $emax;;my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin;;readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 );;},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter:to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 .Device_Events no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .First_init done&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_on *&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_condition &lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_on no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_time &lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .V_Check V 0.3&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVENT state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTFULL lineareingang:state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART1 lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART2 state&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART3  6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 Exec_cmd set linearausgang state [Linearschalter:to_set]&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 Trigger_device lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 Trigger_log off&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 last_event state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:39:56 state active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 to_set 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
MSwitch -Configfile (bei Bedarf)&lt;br /&gt;
&amp;lt;pre&amp;gt;#V V1.54&lt;br /&gt;
#S .Device_Affected -&amp;gt; FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
#S .Device_Affected_Details -&amp;gt; FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 )[S]my $emin=0[S]my $emax=15000[S]my $amin=100[S]my $amax=0[S]$eingang = $emin if $eingang &amp;lt; $emin[S]$eingang = $emax if $eingang &amp;gt; $emax[S]my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin[S]readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 )[S]},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter.to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
#S .Device_Events -&amp;gt; no_trigger&lt;br /&gt;
#S .First_init -&amp;gt; done&lt;br /&gt;
#S .Trigger_Whitelist -&amp;gt; undef&lt;br /&gt;
#S .Trigger_cmd_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_cmd_on -&amp;gt; *&lt;br /&gt;
#S .Trigger_condition -&amp;gt; &lt;br /&gt;
#S .Trigger_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_on -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_time -&amp;gt; &lt;br /&gt;
#S .V_Check -&amp;gt; V 0.3&lt;br /&gt;
#S Trigger_device -&amp;gt; lineareingang&lt;br /&gt;
#S Trigger_log -&amp;gt; off&lt;br /&gt;
#S last_event -&amp;gt; state: 6422&lt;br /&gt;
#S state -&amp;gt; active&lt;br /&gt;
#A MSwitch_Ignore_Types -&amp;gt; notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
#A MSwitch_Include_MSwitchcmds -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Debug -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Help -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Devicecmds -&amp;gt; 1&lt;br /&gt;
#A MSwitch_Extensions -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Webcmds -&amp;gt; 0&lt;br /&gt;
#A room -&amp;gt; Lineartest&lt;br /&gt;
#A MSwitch_Inforoom -&amp;gt; MSwitch&lt;br /&gt;
#A MSwitch_Expert -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Lock_Quickedit -&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Thread über das Modul im {{Link2Forum|Topic=86199|LinkText=FHEM Forum}}&lt;br /&gt;
* {{Link2Forum|Topic=100119|Message=936495|LinkText=Gäste-WLAN der Fritzbox auswerten und Login per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=86199|Message=930133|LinkText=Schalten von vier Kanälen mit einem MSwitch-Device}}&lt;br /&gt;
* {{Link2Forum|Topic=99219|Message=926652|LinkText=Batterie-Überwachung. 1xTäglich per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=101091|Message=945389|LinkText=Licht (Alarm) in einem bestimmten Zeitraum schalten}}&lt;br /&gt;
* {{Link2Forum|Topic=100949|Message=944284|LinkText=Über Dummy-Schalter ein Timer (EIN/AUS) aktivieren}}&lt;br /&gt;
* {{Link2Forum|Topic=103083|Message=967710|LinkText=Ladezeit von Akku ermitteln u. Steckdose entsprechend schalten}}&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31474</id>
		<title>MSwitch</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31474"/>
		<updated>2019-11-01T19:58:01Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* MSwitch_Event_Id_Distributor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[MSwitch]] ist ein Hilfsmodul, welches das Event- und/oder zeitgesteuerte Schalten von mehreren Devices oder das Ausführen von benutzerdefinierten Befehlssequenzen erlaubt.&lt;br /&gt;
&lt;br /&gt;
Die Stärke bzw. das Unterscheidungsmerkmal dieses Moduls liegt in der Konfigurierbarkeit über ein Webinterface. Diese Konfiguration kann jederzeit geändert oder erweitert werden. &lt;br /&gt;
&lt;br /&gt;
Byte09: &#039;&#039;Die Grundidee zu MSwitch kam mir, weil ich bei der Arbeit mit FHEM für meinen Geschmack zu viele Module für die verschiedenen Aufgaben brauchte - zu allem Überfluss alle mit unterschiedlicher Syntax. Zwar ist DOIF hiervon ausgenommen (da hiermit wohl auch fast jede Aufgabe lösbar ist), aber ich konnte mich leider nicht daran gewöhnen und somit wurde jedes DOIF für mich zu einem echten Projekt. Was ich wollte war ein Modul, mit dem ich alles erledigen kann. Daher entschloss ich mich schon nach fast einem knappen Jahr FHEM-Nutzung mein eigenes Modul zu schreiben, welches diese Anforderung erfüllt. MSwitch beinhaltet die Funktionalität aller bisherigen Hilfsmodule wie z.B. Notify, Doif, Watchdog, Dummy,( ab Modulversion 2.2 auch Sequenz ) es lassen sich all deren Funktionen umsetzen.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;MSwitch wird permanent - vorrangig nach meinen Bedürfnissen - weiterentwickelt, gerne nehme ich aber auch Anregungen von anderen Nutzern auf.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=MSwitch&lt;br /&gt;
|ModType=h&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=98_MSwitch.pm&lt;br /&gt;
|ModOwner=Byte09}}&lt;br /&gt;
&lt;br /&gt;
== Grundsätzliche Überlegungen ==&lt;br /&gt;
Um das Modul zu nutzen, muss man zuerst folgende Fragen beantworten:&lt;br /&gt;
&lt;br /&gt;
* Welches Gerät soll auslösen oder zu welcher Zeit soll eine Auslösung erfolgen.&lt;br /&gt;
: Dies ist der Trigger. Jedes Event aus dem Eventmonitor kann als Trigger dienen. Will man mehrere Geräte als gleichzeitige Auslöser betreiben, so muss das Device GLOBAL gewählt und die entsprechenden Geräte angegeben werden (dies erzeugt höhere Systemlast und ist nur im Expert-Modus verfügbar). Weiterhin kann auch zu fest definierten Zeiten, Zufallszeiten oder Intervallen, unabhängig von einem Trigger, geschaltet werden; auch eine Kombination beider Varianten ist möglich. Diese Einstellungen erfolgen im ersten Teil des Webinterfaces.&lt;br /&gt;
&lt;br /&gt;
* Welche Bedingungen sollen bei Auslösung erfüllt sein?&lt;br /&gt;
: Wenn diese Bedingungen erfüllt sind, werden Kommandos ausgelöst. Die Bedingungen werden im zweiten Teil des Webinterfaces eingegeben. Dabei unterscheidet das Modul zwischen zwei Kommando-Kanälen (cmd1 und cmd2) und den dazugehörigen Geräten.&lt;br /&gt;
&lt;br /&gt;
* Welche Kommandos sollen ausgelöst werden?&lt;br /&gt;
: Im dritten Teil des Webinterfaces werden dann die konkreten Kommandos eingegeben. Typischerweise wählt man dabei aus einer Liste der Kommandos aus, die die zugehörigen Geräte insgesamt aufweisen (also so, wie man auf den Geräteseiten selber Kommandos auswählt). Es gibt zudem ein so genanntes FreeCmd, das ein Geräteunabhängiges Kommando zulässt, beispielsweise reinen Perl-Code.&lt;br /&gt;
&lt;br /&gt;
* Welche weiteren Bedingungen sollen noch gelten?&lt;br /&gt;
: Hier sind Ereignisgesteuerte wie auch Zeitgesteuerte Bedingungen möglich. Diese Bedingungen werden auch in dem dritten Teil des Webinterfaces eingetragen. So sind Verzögerungen und Wiederholungen und weitere Bedingungen möglich.&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen, Installation und Grundbefehle ==&lt;br /&gt;
Das MSwitch-Modul ist ohne weitere Voraussetzungen nutzbar und wird derzeit in der Version 2.08 über FHEM Update verteilt. &lt;br /&gt;
&lt;br /&gt;
=== Definition und Einrichtung ===&lt;br /&gt;
Mit Hilfe von MSwitch kann man mehrere Devices gleichzeitig schalten. Diese Schaltungen befinden sich in zwei möglichen Zweigen bei MSwitch. Dabei unterscheidet man im Modul zwischen den beiden Kommandos cmd1 und cmd2. Die zu einem Kommando gehörenden Geräte werden wir auch Zweig nennen. Die einzelnen Devices jedes Zweiges können mit weiteren Schaltbedingungen versehen werden (zeit- oder ereignisgesteuert). &lt;br /&gt;
&lt;br /&gt;
Folgende Möglichkeiten zum definieren des MSwitch Devices stehen zur Verfügung:&lt;br /&gt;
:&amp;lt;code&amp;gt;define &amp;lt;name&amp;gt; MSwitch&amp;lt;/code&amp;gt;&lt;br /&gt;
Es wird ein leeres Device angelegt, das dann komplett über das Webinterface konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das define eines MSwitch Devices generiert lediglich eine &#039;leere Hülle&#039;. Alle relevante Einstellungen werden in Readings und/oder Hashes gespeichert. Daher stehen relevanten Daten &#039;&#039;nicht&#039;&#039; in der fhem.cfg! Vielmehr finden sich diese Daten in der Datei fhem.save (die Speicherung erfolgt durch den Befehl Fhemsave).&lt;br /&gt;
&lt;br /&gt;
=== set-Befehle ===&lt;br /&gt;
Es sind derzeit die folgenden set-Befehle implementiert.&lt;br /&gt;
&lt;br /&gt;
==== set active ====&lt;br /&gt;
Setzt das Device in den Status &#039;active&#039;.&lt;br /&gt;
&lt;br /&gt;
==== set inactive ====&lt;br /&gt;
Setzt das Device in den Status &#039;inactive&#039;, es werden keine Befehle mehr ausgeführt. Dieser Status entspricht dem Attribut &#039;disable&#039;, ist aber nicht mit dem roten Fragezeichen (fhem save) verbunden.&lt;br /&gt;
&lt;br /&gt;
==== set on/off [&amp;lt;parameter&amp;gt;]====&lt;br /&gt;
Setzt das Device in den Status &#039;on&#039; oder &#039;off&#039;. Alle Befehle der &#039;on/off-Zweige&#039; werden ausgeführt.&lt;br /&gt;
Optional kann den Befehlen &#039;on&#039; und &#039;off&#039; ein weiterer Parameter mit übergeben werden. Dieser wird im Reading &#039;Parameter&#039; hinterlegt und es kann sofort in &#039;Freecmds&#039; oder &#039;Conditions&#039; darauf zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
==== set reload_timer ====&lt;br /&gt;
Alle gesetzten Timer werden gelöscht und neu berechnet.&lt;br /&gt;
&lt;br /&gt;
==== set change_renamed &amp;lt;oldname&amp;gt; &amp;lt;newname&amp;gt; ====&lt;br /&gt;
Sollten sich Devicenammen im ausführenden Teil geändert habe (affected Devices, Conditions, etc.) so kann das MSwitch mit diesem Befehl angepasst werden, ohne alle Einstellungen neu einstellen zu müssen.&lt;br /&gt;
&lt;br /&gt;
==== set exec_cmd1 / set exec_cmd1 ID [&amp;lt;ID&amp;gt;] ====&lt;br /&gt;
Bewirkt das sofortige Ausführen des entsprechenden Befehlszweiges. Bei Angabe einer ID werden nur die Befehle mit der entsprechenden ID ausgeführt.&lt;br /&gt;
&lt;br /&gt;
==== set MSwitch_backup ====&lt;br /&gt;
Erstellt eine Backup-Datei aller MSwitch Devices unter ./fhem/MSwitch_backup.cfg.&lt;br /&gt;
&lt;br /&gt;
Daten dieser Datei können im Bedarfsfall für einzelne oder gleichzeitig alle MSwitch Devices wieder zurückgespielt (hergestellt) werden.&lt;br /&gt;
&lt;br /&gt;
==== set del_delays ====&lt;br /&gt;
Löscht alle anstehenden, verzögerten Befehle (delays).&lt;br /&gt;
&lt;br /&gt;
==== set reset_cmd_count:1,2 ====&lt;br /&gt;
Löscht das entsprechende EVT_CMD_COUNT - Reading (entspricht Rückstellung auf &#039;0&#039;).&lt;br /&gt;
&lt;br /&gt;
==== set fakeevent [&amp;lt;device&amp;gt;]:&amp;lt;reading&amp;gt;:&amp;lt;arg&amp;gt; ====&lt;br /&gt;
Beispiel: &amp;lt;device&amp;gt; fakeevent state:on&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ob der Name (&amp;lt;device&amp;gt;) angegeben werden muss, oder nicht, ist abhängig davon, ob auf ein einzelnes Device, oder GLOBAL getriggert wird. Bei GLOBALEN Triggern muss das Device mit angegeben werden. Wird auf ein Device getriggert, so wird das Device automatisch gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit diesem Befehl kann das MSwitch Device neu getriggert werden, indem hier ein Event &#039;gefaked&#039; wird. Das MSwitch Device reagiert dann so, als wäre dieses Event vom getriggerten Gerät generiert worden. &lt;br /&gt;
&lt;br /&gt;
Dieses kann nötig sein, um z.B. einen Watchdog zu realisieren, in dem es nötig ist, dass sich das MSwitch Device mit einem bestimmten Event selber neu triggert - ggf. mit einem entsprechenden Delay (affected Device muss dafür u.A. des MSwitch Device selber sein).&lt;br /&gt;
&lt;br /&gt;
Es wird hierbei KEIN echtes Event generiert welches das System beeinflusst, sondern ausschließlich ein MSwitch-Interner Befehl umgesetzt!&lt;br /&gt;
&lt;br /&gt;
Bei dem Einsatz dieser Möglichkeit sollte das Attribut &#039;MSwitch_Safemode&#039; UNBEDINGT aktiviert sein, da &#039;Experimente&#039; hier schnell in einer Endlosschleife enden können, die nur durch ein Reboot unterbrochen werden kann. &lt;br /&gt;
&lt;br /&gt;
Ggf. werde ich hier sogar eine entsprechende Änderung vornehmen, dass dieser Befehl nur zur Verfügung steht, wenn Safemode aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
=== get-Befehle ===&lt;br /&gt;
==== get show_timer [&amp;lt;show&amp;gt;&amp;lt;delete&amp;gt;] ====&lt;br /&gt;
;Show&lt;br /&gt;
:Zeigt alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren.&lt;br /&gt;
;Delete&lt;br /&gt;
:Löscht alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren. Schaltbefehle basierend auf rein zeitabhängigen Angaben werden neu berechnet und gesetzt.&lt;br /&gt;
&lt;br /&gt;
==== get restore_MSwitch_data [&amp;lt;this_device&amp;gt;&amp;lt;all_devices&amp;gt;] ====&lt;br /&gt;
;this_device&lt;br /&gt;
:Stellt die Daten des Devices aus der Backupdatei wieder her, sofern diese in der Backupdatei gefunden werden (gesucht wird hier nach dem Namen des Devices).&lt;br /&gt;
;all_devices&lt;br /&gt;
:Stellt die Daten aller MSwitch Devices wieder her, sofern diese in der Backupdatei vorhanden sind. Diese Aktion kann einige Zeit in Anspruch nehmen und wird daher im Hintergrund (nonblocking) ausgeführt. Nach Beendigung erfolgt eine Benachrichtigung.&lt;br /&gt;
&lt;br /&gt;
Die Devices sind nach einem Restore funktionsfähig. Empfohlen wird ein Neustart von FHEM.&lt;br /&gt;
&lt;br /&gt;
==== get_config ==== &lt;br /&gt;
Zeigt die Konfigurationsdatei des MSwitchdevices an; diese kann in dem Fenster editiert werden. Das sollte nur von erfahrenen Usern getan werden! Im Normalfall sollte das Device nur über die Weboberfläche konfiguriert werden und eine falsche Konfiguration kann hier zu einem FHEM Absturz führen.&lt;br /&gt;
&lt;br /&gt;
==== get_support_info ==== &lt;br /&gt;
Öffnet ein Fenster mit einer formatierten Ansicht aller Einstellungen des Devices. Bei Supportanfragen sollte dieses immer mit geposted werden.&lt;br /&gt;
&lt;br /&gt;
==== get_MSwitch_preconf ====&lt;br /&gt;
Lädt vorkonfigurierte MSwitch-Devices. Diese Option ist nur dann vorhanden, wenn das Aktualisieren dieser vorkonfigurierten Devices im FHEM Update aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
Diese kann durch ein einmaliges Update erfolgen mit:&lt;br /&gt;
:&amp;lt;code&amp;gt;update all https://raw.githubusercontent.com/Byte009/MSwitch_Addons/master/controls_mswitchaddons.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Webinterface ==&lt;br /&gt;
MSwitch wird im Wesentlichen über das Webinterface eingerichtet. Wählt man das folgende Attribut&lt;br /&gt;
:&amp;lt;code&amp;gt;attr &amp;lt;name&amp;gt; MSwitch_Help 1&amp;lt;/code&amp;gt;&lt;br /&gt;
so wird im Modul selber eine sehr umfangreiche Hilfe angezeigt. Über das gesamte Webinterface hinweg erscheinen kleine Fragezeichen, die man anklicken kann und die beschreiben, was in dem jeweiligen Textfeld sinnvollerweise einzugeben ist bzw. was das Modul an dieser Stelle erwartet.&lt;br /&gt;
&lt;br /&gt;
Das Webinterface besteht aus vier Teilen. Änderungen in jedem Abschnitt müssen in dem jeweiligen Teil bestätigt werden und auch nur diese werden gespeichert. Bevor ein weiterer Teil bearbeitet wird, sollten Änderungen gespeichert werden, sie gehen sonst verloren.&lt;br /&gt;
&lt;br /&gt;
=== Trigger device/time ===&lt;br /&gt;
==== Trigger Device ====&lt;br /&gt;
In diesem Feld wird das Device ausgewählt, dessen Events eine Aktion auslösen sollen. Dazu werden alle verfügbaren Devices in einem Dropdownfeld angeboten.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es eine Auswahl &#039;GLOBAL&#039;, wenn das Attribut &#039;MSwitch_Expert&#039; gesetzt ist. Bei Auswahl dieser Option werden &#039;&#039;&#039;alle&#039;&#039;&#039; von FHEM generierten Events durch das MSwitch Device weiterverarbeitet, eine weitere Begrenzung der aktivierenden Events kann (und sollte) dann in einem folgenden Eingabefeld erfolgen, um die Systemlast zu reduzieren.&lt;br /&gt;
&lt;br /&gt;
==== Trigger Device Global Whitelist ====&lt;br /&gt;
Dieses Feld ist nur verfügbar, wenn als Trigger &#039;GLOBAL&#039; gewählt wurde.&lt;br /&gt;
&lt;br /&gt;
Hier kann die Liste eingehender Events weiter eingeschränkt werden. Es handelt sich um eine Whitelist, d.h., wenn es keine Einträge gibt, werden Events aller Devices verarbeitet. Sobald ein oder mehrere Einträge gemacht werden, werden nur noch Events der hier benannten Devices verarbeitet. Als Angabe können hier Devices benannt werden oder ganze DeviceTypen (z.B. TYPE=FS20). Mehrere Angaben sind durch Komma zu trennen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:MSwitchWebinterface1.png|400px|thumb|right|Webinterface, oben]]&lt;br /&gt;
Im gezeigten Beispiel wurde GLOBAL gewählt, weil nicht ein einzelnes Device, sondern eine Kombination aus zwei Geräten auslösen soll. Es werden also alle Ereignisse betrachtet, wobei die Whitelist dann auf die Devices Schlafzimmer (ein Temperaturmessgerät) und Schlafzimmerfenster (ein [[HM-Sec-SCo Tür-Fensterkontakt, optisch|optischer Kontakt]]) einschränkt. &lt;br /&gt;
&lt;br /&gt;
==== Trigger time ==== &lt;br /&gt;
Es besteht die Möglichkeit, das Modul (neben den Events) zu festen Zeiten auszulösen. Dann wären in die leer stehenden Zeilen bei &amp;quot;at&amp;quot; entsprechende Termine einzutragen. Zeitangaben erfolgen durch [STUNDEN:MINUTEN|TAGE], wobei die Tage von 1-7 gezählt werden (1 steht für Montag, 7 für Sonntag usw.). &lt;br /&gt;
Mehrere Zeitvorgaben können direkt aneinandergereiht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [17:00|1][18:30|23] den Trigger montags um 17 Uhr auslösen und dienstags sowie mittwochs um 18:30 Uhr.&lt;br /&gt;
Bei [00:10*20:00-21:00] würde der Schaltbefehl von 21 Uhr bis 21 Uhr alle 10 Minuten ausgeführt. Bei [?20:00-21:00] würde der Schaltbefehl zu einem zufälligen Zeitpunkt zwischen 20 und 21 Uhr ausgeführt.  [20:00|$we] bedeutet, dass nur am Wochenende um 20:00 geschaltet wird.&lt;br /&gt;
&lt;br /&gt;
==== Trigger conditions ====&lt;br /&gt;
Hier kann die Angabe von Bedingungen erfolgen, die zusätzlich zu dem triggernden Device erfüllt sein müssen.&lt;br /&gt;
Diese Bedingungen sind eng an DOIF-Syntax angelehnt. Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich.&lt;br /&gt;
&lt;br /&gt;
Wird in diesem Feld keine Angabe gemacht, so erfolgt der Schaltvorgang nur durch das triggernde Device ohne weitere Bedingungen.&lt;br /&gt;
&lt;br /&gt;
;Zeitabhängigkeit&lt;br /&gt;
:[19:10-23:00] - Trigger des Devices erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
;Readingabhängige Trigger&lt;br /&gt;
:[Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Trigger des Device erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
:Werden Readings mit Strings abgefragt (on,off,etc.), ist statt des Gleichheitszeichens &amp;quot;=&amp;quot; der Operator &amp;quot;eq&amp;quot; zu nutzen, der String muss in Anführungszeichen &amp;quot;&amp;quot; gesetzt werden.&lt;br /&gt;
;mehrere Beispiele&lt;br /&gt;
:[19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
:[19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
:[10:00-11:00|13] - schaltet Montag und Mittwoch zwischen 10 Uhr und 11 Uhr.&lt;br /&gt;
:[{ sunset() }-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
:{ !$we } löst den Schaltvorgang nur Werktagen an aus.&lt;br /&gt;
:{ $we } löst den Schaltvorgang nur an Wochenenden, Feiertagen aus.&lt;br /&gt;
&lt;br /&gt;
Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (beispielsweise würde dann am Mittwoch noch der Schaltvorgang erfolgen, obwohl als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
Bedingungen in diesem Feld gelten nur für auslösende Trigger eines Devices und haben keinen Einfluss auf zeitgesteuerte Auslöser.&lt;br /&gt;
&lt;br /&gt;
=== Trigger details ===&lt;br /&gt;
[[Datei:MSwitchWebinterface2.png|600px|thumb|right|Webinterface, Mitte]]&lt;br /&gt;
Während im obigen Feld das Device ausgewählt  werden konnte, wird hier das Ereignis festgelegt. Das Eingabefeld besteht aus mehreren Einzelfeldern.&lt;br /&gt;
&lt;br /&gt;
Im abgebildeten Fall wird cmd1 ausgelöst, wenn der Zustand des Schlafzimmerfenster-Sensors meldet, dass das Fenster offen ist. Cmd2 wird ausgelöst, wenn die Temperatur des Schlafzimmersensors unter einen bestimmten Wert fallen wird.&lt;br /&gt;
&lt;br /&gt;
==== execute &#039;cmd1/cmd2&#039;  ====&lt;br /&gt;
Hier kann  aus einer vorbelegten Dropdownliste ausgewählt werden, welches ankommende Event den entsprechenden Befehlszweig auslösen soll. In dieser Liste werden bei entsprechender Einstellung alle ankommenden Events eines vorher definierten Devices gespeichert. In einem weiteren Feld (siehe unten) können Events manuell zugefügt werden.&lt;br /&gt;
&lt;br /&gt;
==== Save incomming events ====&lt;br /&gt;
Bei Aktivierung dieser Option werden alle ankommenden Events des oben definierten Devices (oder Global) gespeichert und in entsprechenden Dropdownlisten angeboten.&lt;br /&gt;
&lt;br /&gt;
Da hier doch erhebliche Datenmengen anfallen können (je nach Device) wird empfohlen, diese Option nach der Konfiguration des Devices zu deaktivieren.&lt;br /&gt;
&lt;br /&gt;
==== add event ====&lt;br /&gt;
Hier besteht die Möglichkeit, unabhängig von der Option, ankommende Events automatisch zu speichern. Manuell Events anzulegen, die in den Dropdownliste zur Auswahl angeboten werden, ohne das entsprechendes Event erst vom Device geliefert werden muss.&lt;br /&gt;
&lt;br /&gt;
Es können mehrere Events gleichzeitig eingegeben werden, eine Trennung erfolgt durch &amp;quot; , &amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Hier ist zu unterscheiden, ob das gewählte triggernde Device ein einfaches Device ist oder ob der Trigger &#039;GLOBAL&#039; ist.&lt;br /&gt;
Bei triggernden Devices können Events in folgendem Formaten zugefügt werden:&lt;br /&gt;
&lt;br /&gt;
- *                                                    - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:wert   (z.b. state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:*      (z.b. state:* )                       - Aktion erfolgt auf die Events &amp;quot;state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:(wert1/wert2/wert3) (z.b. state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;state:left&amp;quot; oder &amp;quot;state:right&amp;quot; etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Falls auf &#039;GLOBALE&#039; Events getriggert wird, muss das auslösende Device vorangestellt werden:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
- *                                                           - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:wert   (z.b. device:state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;device:state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:*      (z.b. device:state:* )                       - Aktion erfolgt auf die Events &amp;quot;device:state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:(wert1/wert2/wert3) (z.b. device:state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;device:state:left&amp;quot; oder &amp;quot;devicestate:right&amp;quot; etc.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Device kann auch hier gegen &amp;quot;*&amp;quot; ersetzt werden (*:state:on). In diesem Fall erfolgt eine Aktion auf alle Events die z.B. &amp;quot;state:on&amp;quot; enthalten, egal welches Device triggert.&lt;br /&gt;
&lt;br /&gt;
==== test event ====&lt;br /&gt;
Dieses Feld wird angeboten, wenn entsprechende vom Triggerdevice gelieferte Events gespeichert wurden.&lt;br /&gt;
&lt;br /&gt;
Durch Auslösen dieser Funktion wird das Event simuliert und entsprechende definierte Aktionen ausgelöst. Diese Funktion dient ausschließlich zum Testen der eingestellten Konfiguration. Alle entsprechenden Befehle werden ausgeführt, als würde das Event real eintreffen.&lt;br /&gt;
&lt;br /&gt;
==== apply filter to saved events ====&lt;br /&gt;
Beschreibung folgt&lt;br /&gt;
&lt;br /&gt;
==== clear saved event ====&lt;br /&gt;
Es werden alle gespeicherten Events gelöscht.&lt;br /&gt;
&lt;br /&gt;
Ausnahme: Events, die als Trigger eingestellt sind, bleiben erhalten.&lt;br /&gt;
&lt;br /&gt;
=== Affected devices ===&lt;br /&gt;
[[Datei:MSwitch_Screen_5.png|mini|rechts|affected devices]]&lt;br /&gt;
Dieser Abschnitt beinhaltet die Auswahl der Devices, die auf ein Event reagieren sollen.&lt;br /&gt;
&lt;br /&gt;
In dem Auswahlfeld werden alle Devices angeboten, die eines der folgenden Kriterien erfüllen:&lt;br /&gt;
# Die Abfrage &amp;quot;set Device ?&amp;quot; liefert einen Befehlssatz&lt;br /&gt;
# Das Attribut &#039;webcmd&#039; des Devices enthält Einträge&lt;br /&gt;
# Das Attribut &#039;MSwitch_Activate_MSwitchcmds&#039; ist aktiviert und das Attribut &#039;MSwitchcmds&#039; des betreffenden Devices enthält einen Befehlssatz&lt;br /&gt;
&lt;br /&gt;
Einzige Ausnahme ist der erste Listeneintrag &#039;FreeCMD&#039;. Die Auswahl dieses Eintrages bietet später die Möglichkeit Befehle auszuführen, die nicht an ein Device gebunden sind. Der Code in einem FreeCmd kann entweder reiner FHEM-Code sein ( set device on ) oder reiner Perl-Code. Wenn es sich um reinen Perl-Code handelt, ist dieser in geschweifte Klammen zu setzen { Perl-Code }.&lt;br /&gt;
&lt;br /&gt;
=== Device actions ===&lt;br /&gt;
[[Datei:Webinterface3.png|mini|rechts|device_actions]]&lt;br /&gt;
Hier stellt man die auszuführenden Aktionen der eingestellten Devices ein. Im ersten Abschnitt oben befindet sich ein FreeCmd, mit dem beliebige Kommandos eingetragen werden können. Im abgebildeten Beispiel ist dies sogar selbst definierter Perl-Code (die Funktion DebianMail sendet eine Mail). &lt;br /&gt;
&lt;br /&gt;
==== MSwitch cmd1/cmd2:  ====&lt;br /&gt;
Man wählt den Befehl aus dem betreffenden Device aus. Bei freien Textfeldern (wie im Fall des FreeCmd) wird der Befehl eingegeben.&lt;br /&gt;
&lt;br /&gt;
Es werden alle verfügbaren Befehle des Devices zur Auswahl angeboten. Je nach Attribut-Einstellungen werden Einträge aus entsprechenden &#039;webcmds&amp;quot; oder &#039;MSwitchcmds&#039; einbezogen. In Abhängigkeit des Befehls stehen unter Umständen weitere Felder oder Widgets zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
05.04.2018 NEU: Auswahlfeld &#039;MSwitchtoggle&#039; -&amp;gt; Beschreibung wird noch ergänzt !&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 condition  ====&lt;br /&gt;
Mit diesem Feld kann die Ausführung des Befehls von weiteren Bedingungen abhängig gemacht werden. Bei der Abfrage von Readings nach Strings (on, off, etc.) ist statt &amp;quot;=&amp;quot; &amp;quot;eq&amp;quot; zu nutzen und der String muss in &amp;quot;x&amp;quot; gesetzt werden. Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
#Zeitabhängiges schalten: [19:10-23:00] - Schaltbefehl erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
#Readingabhängiges schalten [Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Schaltbefehl erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
&lt;br /&gt;
Soll nur an bestimmten Wochentagen geschaltet werden, muss eine Zeitangabe gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [10:00-11:00|13] den Schaltvorgang nur Montag und Mittwoch zwischen 10 Uhr und 11 Uhr auslösen. Hierbei zählen die Wochentage von 1-7 für Montag-Sonntag.&lt;br /&gt;
&lt;br /&gt;
Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich:&lt;br /&gt;
* [19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
* [19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
* [{sunset()}-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
* { !$we } löst den Schaltvorgang nur Werktagen aus&lt;br /&gt;
* { $we } löst den Schaltvorgang nur Wochenenden, Feiertagen aus&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung:&#039;&#039;&#039; Bei Anwendung der geschweiften Klammern zur Einleitung eines Perl Ausdrucks ist unbedingt auf die Leerzeichen hinter und vor der Klammer zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (zum Beispiel würde auch am Mittwoch noch der Schaltvorgang erfolgen, wenn als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
; $EVENT:&lt;br /&gt;
: Die Variable EVENT enthält den auslösenden Trigger, d.h. es kann eine Reaktion in direkter Abhängigkeit zum auslösenden Trigger erfolgen.&lt;br /&gt;
&lt;br /&gt;
[$EVENT] eq &amp;quot;state:on&amp;quot; würde den Kommandozweig nur dann ausführen, wenn der auslösende Trigger &amp;quot;state:on&amp;quot; war. Wichtig ist dieses, wenn bei den Triggerdetails nicht schon auf ein bestimmtes Event getriggert wird, sondern hier durch die Nutzung eines Wildcards (*) auf alle Events getriggert wird, oder auf alle Events eines Readings z.B. (state:*).&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 delay  ====&lt;br /&gt;
Ein Eintrag in diesem Feld führt zur verzögerten Ausführung des Befehls nach Eintreffen des Events. Dabei kann der Befehl ohne weitere Prüfung der Bedingung ausgelöst werden. Es ist aber auch möglich, dass die Bedingung bei Ausführung erneut geprüft wird. Die Zeitangabe muss im Format hh:mm:ss vorliegen.&lt;br /&gt;
&lt;br /&gt;
Statt einer unmittelbaren Zeitangabe kann hier auch ein Verweis auf ein Reading eines Devices erfolgen :&amp;lt;br&amp;gt;&lt;br /&gt;
[NAME.reading] des Devices -&amp;gt;z.B. [dummy.state]&lt;br /&gt;
&lt;br /&gt;
==== add action  ====&lt;br /&gt;
Mit diesem Button kann ein weiteres Eingabefeld für das entsprechende Device angelegt werden, um z.B. einen weiteren Befehl (ggf.) zeitverzögert auszuführen.&lt;br /&gt;
&lt;br /&gt;
==== delete this action  ====&lt;br /&gt;
Mit diesem Button wird der entsprechende Befehl für das Device gelöscht.&lt;br /&gt;
&lt;br /&gt;
==== check condition  ====&lt;br /&gt;
[[Datei:MSwitch_Screen_7.png|mini|rechts|check]]&lt;br /&gt;
Die angegebenen &#039;conditions&#039; werden in Zusammenhang mit ggf. ausgewählten Devices auf Syntax und Ergebnis geprüft. Es erfolgt eine Ausgabe des Prüfungsergebnisses.&lt;br /&gt;
&lt;br /&gt;
==== Repeat und Repeatdelay ====&lt;br /&gt;
Man kann mehrfache Wiederholungen erzwingen. Repeat gibt dabei an, wie oft das Kommando wiederholt wird (Anzahl). Repeatdelay gibt an, wie viel Sekunden zwischen einzelnen Wiederholungen liegen sollen.&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Folgende Attribute stehen zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Debug (0:1:2:3:4) ===&lt;br /&gt;
0 - Abgeschaltet&amp;lt;br&amp;gt;&lt;br /&gt;
1 - Schaltet Felder zum testen der Conditionstrings etc. an&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Alle ausgehenden Befehle werden nur simuliert und nicht ausgeführt. Es erfolgt eine Protokollierung in einer separaten Datei . Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Es erfolgt eine Protokollierung in einer separaten Datei . Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
4 - erweiterte Debugfunktion (nur für Entwicklung - wechselnde Funktion )&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Expert (0:1) ===&lt;br /&gt;
In der Liste der möglichen Trigger erscheint das Selectfeld &#039;GLOBAL&#039;. Dieses ermöglicht das Setzen eines Triggers auf alle Events und damit nicht nur auf einzelne Devices. In einem weiteren Feld kann eine weitere Selektion der triggernden Events erfolgen.&lt;br /&gt;
&lt;br /&gt;
Es stehen weitere Felder &#039;Repeats&#039; und &#039;Repeatdelay in sec&#039; zur Verfügung. Eine hier getätigte Einstellung bewirkt X-fache Wiederholung von gesetzten Befehlen im Abstand der gesetzten Sekunden.&lt;br /&gt;
&lt;br /&gt;
Weiterhin kann über das Auswahlfeld &#039;priotity&#039; bei jedem &#039;affectes device&#039; die Reihenfolge beim abarbeiten der Befehle beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequenz &amp;lt;Suchmuster&amp;gt; ===&lt;br /&gt;
In diesem Attribut können ein oder mehrere Suchmuster angegeben werden ,die eine Schaltsequenz darstellen und vom Device erkannt werden.&lt;br /&gt;
&lt;br /&gt;
Die Angabe muss folgende Syntax haben:&lt;br /&gt;
:&amp;lt;code&amp;gt;Device1:reading1:event1 Device1:reading1:event1-2 Device1:reading1:event1-3/..../....&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mehrere Suchmuster müssen durch &amp;quot;/&amp;quot; getrennt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
:&amp;lt;code&amp;gt;Dummy:state:on Dummy:state:off Dummy:state:on&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erkennt das Device dieses Suchmuster in den Schaltvorgängen des Devices (Dummy), wird das Reading &amp;quot;SEQUENCE&amp;quot; auf &amp;quot;match&amp;quot; gesetzt, das Reading &amp;quot;SEQUENCE_NUMBER&amp;quot; auf die Nummer der gefundenen Sequenz, wenn es mehrere Suchmuster gibt. Beide Readings können in den &amp;quot;Conditions&amp;quot; eines Schaltbefehles abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequence_time &amp;lt;Zeit in Sekunden&amp;gt; ===&lt;br /&gt;
Beinhaltet die Zeit in Sekunden, die es dauern darf, um eine Sequenz vollständig auszuführen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Extensions (0:1) ===&lt;br /&gt;
Es wird eine zusätzliche Schaltoption &#039;MSwitchToggle&#039; in den Geräten angeboten. Diese kann genutzt werden, wenn zuschaltende Geräte eine Togglefunktion nicht von Haus aus anbieten.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe muss in folgendem Format gemacht werden:&lt;br /&gt;
:&amp;lt;code&amp;gt;on/off/state/suchmuster1/suchmuster2&amp;lt;/code&amp;gt;, wobei die letzten drei Angaben optional sind.&lt;br /&gt;
&lt;br /&gt;
Funktion: Bei Ausführung des Befehls wird das Gerät &#039;on&#039; oder &#039;off&#039; geschaltet (on/off), Voraussetzung ist, dass der &#039;state&#039; dieses Gerätes auch den &#039;state on&#039; oder &#039;off&#039; annimmt. Sollte dieses nicht der Fall sein, so kann mit dem Feld &#039;state&#039; angegeben werden, in welchem Reading der aktuelle Status vorkommt und wie dieser lautet (suchmuster1/suchmuster2). Dieses &#039;state&#039; kann mehrere Angaben enthalten, das Vorkommen der Suchmuster ist aber Voraussetzung.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Delete_Delays (0:1) ===&lt;br /&gt;
Bewirkt das Löschen aller anstehende Timer (Delays) bei dem Auftreten eines erneuten, passenden Events. Bei der Option &#039;0&#039; bleiben bereits gesetzte Delays aus einem vorherigen, getriggertem Event erhalten und werden ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1)&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Devicecmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz liefern (bei Abfrage set DEVICE ?).&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Webcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut Webcmd hinterlegt haben. Die in Webcmd hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten.&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Activate_MSwitchcmds (0:1) ===&lt;br /&gt;
Fügt jedem vorhandenen Device as Attribut &#039;MSwitchcmd&#039; hinzu.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_MSwitchcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut MSwitchcmds hinterlegt haben. Die in MSwitchcmds hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten. Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr Angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Lock_Quickedit (0:1) ===&lt;br /&gt;
Voreinstellung für die Auswahlliste &#039;Affected Devices&#039;. Bei der Option (1) ist diese voreingestellt gesperrt und kann nur über einen zusätzlichen Button geändert werden. Da es sich hier um ein Feld mit der Möglichkeit einer Mehrfacheingabe handelt handelt ist die Voreinstellung 1, um versehentliche nicht gewünschte Änderungen zu vermeiden (Auswahl einer Option ohne &#039;Strg&#039; bewirkt das löschen aller bereits gesetzten Optionen).&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay (0:10:20:30:60) ===&lt;br /&gt;
Diese Einstellung beeinflusst den Start von MSwitch nach einem FHEM Start. MSwitch ignoriert für die angegebene Zeit in Sekunden alle eingehenden Events um u.a. Startverzögerungen zu vermeiden. Bei nicht gesetztem Attribut gilt hier eine Zeit von 30 Sekunden. Diese sollte auch nur in Ausnahmefällen bzw. bei besonderem Bedarf geändert werden.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (30).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Ignore_Types ===&lt;br /&gt;
Beinhaltet eine Liste von Device&#039;&#039;typen&#039;&#039;, die in den Auswahllisten &#039;&#039;nicht&#039;&#039; dargestellt werden. Hier ist es sinnvoll, Devicetypen einzutragen, die in aller Regel nicht geschaltet werden oder nicht geschaltet werden können, um die Auswahllisten übersichtlicher zu halten. Einzelne Devicetypen sind durch Leerzeichen zu trennen.&lt;br /&gt;
&lt;br /&gt;
Voreinstellung: notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe kann hier in 2 Arten getätigt werden:&lt;br /&gt;
# eine Liste von devicetypen.&lt;br /&gt;
# Angabe einer devspec z.B. &amp;quot;TYPE=watchdog&amp;quot;. Hier ist zu beachten, dass in diesem Fall alle Geräte in die Ignoreliste einbezogen werden, die NICHT der devspec entsprechen. Weiterhin muss die devspec in Anführungszeichen gesetzt werden!&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Trigger_Filter ===&lt;br /&gt;
Beinhaltet eine Liste von Events, die bei eingehenden Events unberücksichtigt bleiben. Diese werde dann auch nicht gespeichert.&lt;br /&gt;
&lt;br /&gt;
Hier kann mit Wildcards (*) gearbeitet werden. Einzelne Events sind durch Komma &#039;,&#039; zu trennen.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (keine).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Wait (sec)===&lt;br /&gt;
Bei gesetztem Attribut (Zeit in Sekunden) nimmt Das MSwitch Device für den eingestellten Zeitraum keine Befehle mehr entgegen und ignoriert eingehende Events&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Event_Id_Distributor ===&lt;br /&gt;
Dieses Attribut hat nur dann eine Funktion, wenn auch das Attribut &#039;MSwitchExpert&#039; auf &#039;1&#039; gesetzt ist.&lt;br /&gt;
Hier können verschiedene auslösende Events auf Aktionen mit angegebenen IDs umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Sollte bei den &#039;trigger details :&#039; in einem Zweig ( cmd1 ) z.B. auf mehrere Events getriggert werden ( regex z.B. state:(on|off) ) so werden für beide Events jeweils der Zweig &#039;cmd1&#039; - alle  Aktionen ohneID - ausgeführt. Durch entsprechende Einträge kann für entsprechende Events auf eine Aktion umgeleitet werden, für die eine ID definiert ist. Die Syntax lautet:&lt;br /&gt;
:&amp;lt;code&amp;gt;state:on=&amp;gt;cmd1 ID 1,2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden bei auslösendem Event &#039;state:on&#039; nur die Aktionen aus cmd1 mit den IDs 1 und 2 ausgeführt. Mehrere Angaben sind durch new Line zu trennen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Selftrigger_always (0,1)===&lt;br /&gt;
(dieses Attribut steht ab Modulversion 2.5 zur Verfügung)&lt;br /&gt;
&lt;br /&gt;
Die Aktivierung dieses Attributes (1) bewirkt , dass alle SET Aktionen des Devices einen (internen) Event auslösen, auf die das Device selber reagiert. Diese Option kann zusätzlich zu einem vorhandenen Trigger aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Diese Events sind lediglich Deviceintern , d.H es werden keine Modulübergreifenden Events ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Auftretende und auswertbare interne Events haben immer folgendes Format und können darüber augewertet weden.&lt;br /&gt;
&lt;br /&gt;
MSwitch_Self:aktion:wert &lt;br /&gt;
MSwitch_Self:pct:100&lt;br /&gt;
&lt;br /&gt;
Es werden nur interne Events für set-Aktionen ausgelöst , die im Attribut setlist hinterlegt sind.&lt;br /&gt;
&lt;br /&gt;
Als weitere Besonderheit unterliegen diese internen Events nicht dem &#039;wait&#039; Befehl/Attribut&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Mode (Notify,Full,Toggle,Dummy)===&lt;br /&gt;
Schaltet das Modul zwischen verschiedenen Modi um, mit entsprechend angepasster Weboberfläche.&lt;br /&gt;
&lt;br /&gt;
==== Notify ====&lt;br /&gt;
Das Device kann nicht manuell umgeschaltet werden, es gibt nur zwei ausführbare Zweige (execute &#039;cmd1&#039; commands und execute &#039;cmd2&#039; commands). Der Status des Devices wird nicht als &#039;on&#039; oder &#039;off&#039; angezeigt, sondern lediglich als &#039;active&#039;&lt;br /&gt;
&lt;br /&gt;
Dieser Mode ist am ehesten mit einem Notify zu Vergleichen.&lt;br /&gt;
==== Full ====&lt;br /&gt;
Es stehen alle Funktionen zur Verfügung.&lt;br /&gt;
==== Toggle ====&lt;br /&gt;
Sehr vereinfachter Mode. Es stehen keine verschiedenen Zweige zur Verfügung. Hier ist das Device manuell schaltbar und wird bei jedem definierten Event &#039;Umgeschaltet&#039;, entsprechend definierte Befehle für &#039;cmd1&#039; oder &#039;cmd2&#039; werden ausgeführt.&lt;br /&gt;
==== Dummy====&lt;br /&gt;
ACHTUNG: Funktionsänderung mit V2.61&lt;br /&gt;
&lt;br /&gt;
Der Mode &#039;Dummy&#039; ist ein eingeschränkter Modus. &lt;br /&gt;
Dieser bietet die Funktionalität eines Dummys kombiniert mit der Funktionalität eines Notifys und kann somit die gerne genutzte Kombination Dummy-Notify gegen ein Device ersetzen.&lt;br /&gt;
&lt;br /&gt;
Achtung: Devices die einmal in dem Modus &#039;Dummy&#039; gesetzt wurden können nicht wieder in einen anderen Mode geschaltet werden ! &lt;br /&gt;
&lt;br /&gt;
Der Dummy-Mode kann nur in einem neu angelegtem, leeren MSwitch aktiviert werden. Sobald ein angelegtes MSwitch einmal verändert wurde (modify trigger etc.) ist ein Umschalten nicht mehr möglich und die Option nicht mehr verfügbar.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Condition_Time (0,1)===&lt;br /&gt;
In der Grundeinstellung (0) werden für das zeitgesteuerte Schalten keine definierten Conditionen im Feld &#039;Trigger condition&#039; überprüft, sondern die Schaltbefehle werden in jedem Fall ausgeführt. Mit der Einstellung (1) wird diese Überprüfung auch für zeitgesteuerte Befehle zugeschaltet.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Time (HH:MM:SS-HH:MM:SS)===&lt;br /&gt;
Bei Aktivierung wird vor jedem Ausführen eines verzögerten Befehls ( Delay ) eine Zufallszeit generiert, die im Rahme der hier angegebenen Zeitspanne liegt. Auf diese Zufallszahl kann in den Delays zugegriffen werden, durch die Angabe &#039;[random]&#039; statt einer direkten Zeitangabe. Bei nicht gesetztem Attribut ergibt die Angabe von &#039; [random] &#039; hier immer &#039;00:00:00&#039;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Number ===&lt;br /&gt;
Bei Aktivierung dieses Attributes (der Inhalt kann einen beliebige Zahl sein) werden vom Device 2 Readings angelegt (Device:RandomNr) und (Device:RandomNr1). RandomNr wird vor jedem Ausführen eines Befehls aktualisiert und neu generiert, d.h wenn ein MSwitch Device mehrere Geräte schaltet, wird (auch in einem Durchgang) vor jedem Befehl dieses Reading neu gesetzt. RandomNr1 wird lediglich bei Ausführung des MSwitch Devices einmal neu gesetzt, d.h. nicht vor jedem Befehl der ausgeführt wird.&lt;br /&gt;
Die Readings werden mit einer Zufallszahl zwischen 0 und dem hier eingestellten Wert gesetzt.&lt;br /&gt;
&lt;br /&gt;
Auf diese Readings kann in jeder Condition mit z.B. &#039;[$NAME:ReadingNr1] = 1&#039; zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
D.h., das in der Condition angegebene Reading ( [$NAME:ReadingNr1] ) muss in diesem Fall den Wert 1 angenommen haben, ansonsten wird der Befehl nicht ausgeführt. &lt;br /&gt;
Der Befehl wird somit nur mit einer Wahrscheinlichkeit von 1 zu ( gesetzter Wert im Attr. ) ausgeführt.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Reset_EVT_CMD1(2)_COUNT ===&lt;br /&gt;
Bei Aktivierung dieses Attributes steht in den Readings das Reading &#039;EVT_CMD1_COUNT&#039; bzw. &#039;EVT_CMD2_COUNT&#039; zur Verfügung. Dieses kann in den Conditions genutzt werden, um z.B. nur bei jedem x-ten Eintreffen eines auslösenden Events einen Befehl auszuführen. Bei jedem Eintreffen eines gültigen Events werden die Zähler um 1 erhöht (für den jeweiligen Zweig). &lt;br /&gt;
Ist hier der Wert &#039;0&#039; eingetragen, wird der Zähler fortlaufend (endlos) erhöht. Wird ein Wert größer 0 eingetragen, wird der Zähler mit Erreichen dieses Wertes automatisch wieder auf Null gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit Löschen dieses Attributes werden die entsprechenden Readings ebenfalls gelöscht.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Safemode (0:1)===&lt;br /&gt;
Bietet einen (gewissen) Schutz vor falschen Konfigurationen und somit entstehenden Endlosschleifen.&lt;br /&gt;
Bei aktiviertem Attribut (1) erkennt das Modul Endlosschleifen eines Devices und beendet diese.&lt;br /&gt;
&lt;br /&gt;
In diesem Fall erfolgt ein Logeintrag und das Device wird per Attribut auf &#039;Disabled&#039; gesetzt.&lt;br /&gt;
Es wird ein letztes Event generiert, auf das reagiert werden kann:&lt;br /&gt;
:&amp;lt;code&amp;gt;2018-05-31 09:39:21 MSwitch &amp;lt;NAME&amp;gt; Safemode: on&amp;lt;/code&amp;gt;&lt;br /&gt;
Im Webinterface erfolgt bei betroffenem Device ein entsprechender Hinweis.&lt;br /&gt;
&lt;br /&gt;
In der Grundkonfiguration ist dieses Attribut nicht gesetzt, es empfiehlt sich aber, bei neuen (komplizierten) Devices, dieses - zumindest anfänglich - zu aktivieren.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Read_Log(0:1)===&lt;br /&gt;
Ermöglicht den Zugriff auf das Logfile als Trigger.&lt;br /&gt;
&lt;br /&gt;
Hier gibt es mehrere Konfigurationsmöglichkeiten:&lt;br /&gt;
* Bei aktiviertem Attribut enthält die Auswahl des Triggerdevices die Option &#039;LOGFILE&#039;. Bei dieser Auswahl werde alle Logeinträge erkannt und in ein internes Event umgewandelt, auf das regiert werden kann.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl &#039;GLOBAL&#039; im &#039;Trigger_Device&#039; wird auf ALLE Events und alle Logeinträge reagiert.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl eines bestimmten Devices im &#039;Trigger_Device&#039; wird auf alle Events  und auf alle Logeinträge des gewählten Devices reagiert. Hier ist zu beachten, dass FHEM mir keine Möglichkeit bietet, wirklich herauszufinden, welches Device denn nun einen Logeintrag generiert hat. D.h., dieses wird vom Vorhandensein des Namens im Logeintrag abhängig gemacht und MSwitch reagiert nur dann auf einen Logeintrag, wenn der Name des Devices in diesem Eintrag vorhanden ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Help(0:1)===&lt;br /&gt;
Schaltet Hilfebuttons zu den einzelnen Eingabefeldern an oder aus.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Comments(0:1)===&lt;br /&gt;
Schaltet Kommentarfelder zu den einzelnen &#039;affected_devices an.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_generate_Events(0:1)===&lt;br /&gt;
Reduziert bei Einstellung &#039;1&#039; die vom MSwitch-Devices erzeugten Events auf ein absolutes Minimum. Insbesondere bei Verwendung von &#039;MSwitch_Read_Log&#039; zu empfehlen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay ===&lt;br /&gt;
Bestimmt die Verzögerungszeit des MSwitches nach FHEM-Start in Sekunden. In diesem Zeitraum reagiert das ??Event??(Red: ist hier &amp;quot;Device&amp;quot; gemeint?) nicht auf Events. Die Vorgabe ist hier zehn Sekunden. Diese wird auch dann angenommen, wenn das Attribut nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Inforoom ===&lt;br /&gt;
Mit diesem Attribut wird die Raumansicht eines mit dem Attribut bestimmten Raumes verändert. Dadurch sollen die wichtigsten Informationen aller MSwitch-Devices auf eine Seite dargestellt werden. Zur Nutzung sollten alle MSwitch-Devices (zusätzlich) in einen Raum sortiert werden und dieser Raum im Attribut eingestellt werden.&lt;br /&gt;
&lt;br /&gt;
Wichtig: Eine Änderung dieses Attributes bewirkt immer eine Änderung dieses Attributes in &#039;&#039;allen&#039;&#039; MSwitch devices: Es muss nur in einem Device gesetzt oder gelöscht werden um alle Devices zu erfassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
MSwitch_Screen_1.png|Raumansicht des Raumes MSwitch mit gesetztem Attribut &#039;MSwitch&#039;&lt;br /&gt;
MSwitch_Screen_2.png|Raumansicht des Raumes MSwitch ohne gesetztes Attribut&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es werden folgende Informationen bereitgestellt:&lt;br /&gt;
* Infobutton zeigt den im Device gespeicherten Textes des Attributes &#039;comment&#039;&lt;br /&gt;
* Device und Events, die das Device triggern&lt;br /&gt;
* Zeiten, zu denen verschiedene Zweige des Devices ausgeführt werden&lt;br /&gt;
* Devices, die durch das MSwitch Device geschaltet werden&lt;br /&gt;
* State des Devices&lt;br /&gt;
&lt;br /&gt;
== Integrierte Funktionen ==&lt;br /&gt;
&lt;br /&gt;
=== Average ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
=== Tendency ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[TEND&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;Mindestwert&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[TEND2:countdown] &amp;gt; 2&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Es wird jeweils der Durchschnitt von 2 Wertepaaren gebildet. In diesem Fall werden die letzten 4 Werte herangezogen.&amp;lt;br&amp;gt;&lt;br /&gt;
Paar 1 = Aktueller und letzter Wert, Paar 2 = Die 2 vorherigen Werte.&amp;lt;br&amp;gt;&lt;br /&gt;
Bei TEND3 werden die letzten 6 Werte zur Paarbildung genutzt.&lt;br /&gt;
&lt;br /&gt;
Mindestwert:&lt;br /&gt;
Der Wertunterschied zwischen den Wertepaaren, der minimal erreicht sein muss, um eine Tendenz zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Rechenzeichen (&amp;gt;&amp;lt;):&lt;br /&gt;
Dieses ist hier nicht als Rechenzeichen zu werten, sonder als Tendenz-Anzeige. ( &amp;lt; es wird nach fallender Tendenz gesucht / &amp;gt; sucht nach steigender Tendenz).&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolgt einmalig bei Erkennung der gesuchten Tendenz.&lt;br /&gt;
Danach erfolgt keine Schaltung mehr, solange bis eine Tendenz-Umkehr erfolgt ist.&lt;br /&gt;
Erst dann erfolgt wieder eine Schaltung bei erneuter Tendenz-Umkehr in gesuchte Richtung.&lt;br /&gt;
&lt;br /&gt;
=== Difference ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[DIFF&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;differenz&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[DIFF2:countdown] &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Gespeicherter Wert (in diesem Fall der vorletzte).&lt;br /&gt;
&lt;br /&gt;
Differenz:&lt;br /&gt;
Geforderter Differenz zwischen aktuellem und vorletztem Wert.&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolg wenn diese Bedingung &#039;wahr&#039; ist.&lt;br /&gt;
&lt;br /&gt;
Folgende Readings werden zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
DIFFERENCE (true/false) - Schaltbedingung erkannt ja/nein&lt;br /&gt;
&lt;br /&gt;
DIFFDIRECTION (up/down) - Richtung der erkannten Bedingung (steigend/fallend)&lt;br /&gt;
&lt;br /&gt;
=== Increase ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
== Tipps, Tricks, Kurzbeispiele ==&lt;br /&gt;
Wird stetig ergänzt .&lt;br /&gt;
&lt;br /&gt;
=== Blinken - Falls nicht im Device vorhanden ===&lt;br /&gt;
[[Datei:MSwitch MSwitchblink.png|center|704px]]&lt;br /&gt;
&amp;lt;br clear=all&amp;gt;&lt;br /&gt;
Lässt ein beliebiges Device 5 mal togglen, mit einem Intervall von 0.5 Sekunden (Blinkzeit somit 2,5 Sekunden)&amp;lt;br&amp;gt;&lt;br /&gt;
Die MSwitchtoggle-Funktion muss per ATTR aktiviert werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Die Repeatfunktion ist nur im Expertmode verfügbar, auch per ATTR einstellbar.&lt;br /&gt;
&lt;br /&gt;
=== Linearschalter ===&lt;br /&gt;
Umsetzung eines Linearschalters mit MSwitch.&lt;br /&gt;
&lt;br /&gt;
Eingang: Beliebiges Reading als numerischer Wert.&lt;br /&gt;
&lt;br /&gt;
Ausgang: Wird entsprechend Linear / oder umgekehrt Linear zum Eingang geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgend die Rawdefinition des MSwitchdevices und zweier Dummys (selbsterklärend)&lt;br /&gt;
&lt;br /&gt;
Alle Devices werden im Raum Lineartest angelegt, die Dummy müssen zuerst angelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod linearausgang dummy&lt;br /&gt;
attr linearausgang room Lineartest&lt;br /&gt;
attr linearausgang setList state:slider,0,1,100&lt;br /&gt;
attr linearausgang webCmd state&lt;br /&gt;
setstate linearausgang state 57&lt;br /&gt;
setstate linearausgang 2018-06-06 18:06:12 state state 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod lineareingang dummy&lt;br /&gt;
attr lineareingang room Lineartest&lt;br /&gt;
attr lineareingang setList state:slider,0,1,15000&lt;br /&gt;
attr lineareingang webCmd state&lt;br /&gt;
setstate lineareingang 6422&lt;br /&gt;
setstate lineareingang 2018-06-06 18:06:12 state 6422&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod Linearschalter MSwitch lineareingang  # linearausgang FreeCmd&lt;br /&gt;
attr Linearschalter MSwitch_Debug 0&lt;br /&gt;
attr Linearschalter MSwitch_Delete_Delays 1&lt;br /&gt;
attr Linearschalter MSwitch_Expert 0&lt;br /&gt;
attr Linearschalter MSwitch_Extensions 0&lt;br /&gt;
attr Linearschalter MSwitch_Help 0&lt;br /&gt;
attr Linearschalter MSwitch_Ignore_Types notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
attr Linearschalter MSwitch_Include_Devicecmds 1&lt;br /&gt;
attr Linearschalter MSwitch_Include_MSwitchcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Include_Webcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Inforoom MSwitch&lt;br /&gt;
attr Linearschalter MSwitch_Lock_Quickedit 1&lt;br /&gt;
attr Linearschalter MSwitch_Mode Notify&lt;br /&gt;
attr Linearschalter room Lineartest&lt;br /&gt;
&lt;br /&gt;
setstate Linearschalter active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:03:50 .Device_Affected FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:04:35 .Device_Affected_Details FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 );;my $emin=0;;my $emax=15000;;my $amin=100;;my $amax=0;;$eingang = $emin if $eingang &amp;lt; $emin;;$eingang = $emax if $eingang &amp;gt; $emax;;my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin;;readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 );;},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter:to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 .Device_Events no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .First_init done&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_on *&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_condition &lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_on no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_time &lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .V_Check V 0.3&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVENT state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTFULL lineareingang:state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART1 lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART2 state&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART3  6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 Exec_cmd set linearausgang state [Linearschalter:to_set]&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 Trigger_device lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 Trigger_log off&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 last_event state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:39:56 state active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 to_set 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
MSwitch -Configfile (bei Bedarf)&lt;br /&gt;
&amp;lt;pre&amp;gt;#V V1.54&lt;br /&gt;
#S .Device_Affected -&amp;gt; FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
#S .Device_Affected_Details -&amp;gt; FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 )[S]my $emin=0[S]my $emax=15000[S]my $amin=100[S]my $amax=0[S]$eingang = $emin if $eingang &amp;lt; $emin[S]$eingang = $emax if $eingang &amp;gt; $emax[S]my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin[S]readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 )[S]},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter.to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
#S .Device_Events -&amp;gt; no_trigger&lt;br /&gt;
#S .First_init -&amp;gt; done&lt;br /&gt;
#S .Trigger_Whitelist -&amp;gt; undef&lt;br /&gt;
#S .Trigger_cmd_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_cmd_on -&amp;gt; *&lt;br /&gt;
#S .Trigger_condition -&amp;gt; &lt;br /&gt;
#S .Trigger_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_on -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_time -&amp;gt; &lt;br /&gt;
#S .V_Check -&amp;gt; V 0.3&lt;br /&gt;
#S Trigger_device -&amp;gt; lineareingang&lt;br /&gt;
#S Trigger_log -&amp;gt; off&lt;br /&gt;
#S last_event -&amp;gt; state: 6422&lt;br /&gt;
#S state -&amp;gt; active&lt;br /&gt;
#A MSwitch_Ignore_Types -&amp;gt; notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
#A MSwitch_Include_MSwitchcmds -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Debug -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Help -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Devicecmds -&amp;gt; 1&lt;br /&gt;
#A MSwitch_Extensions -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Webcmds -&amp;gt; 0&lt;br /&gt;
#A room -&amp;gt; Lineartest&lt;br /&gt;
#A MSwitch_Inforoom -&amp;gt; MSwitch&lt;br /&gt;
#A MSwitch_Expert -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Lock_Quickedit -&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Thread über das Modul im {{Link2Forum|Topic=86199|LinkText=FHEM Forum}}&lt;br /&gt;
* {{Link2Forum|Topic=100119|Message=936495|LinkText=Gäste-WLAN der Fritzbox auswerten und Login per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=86199|Message=930133|LinkText=Schalten von vier Kanälen mit einem MSwitch-Device}}&lt;br /&gt;
* {{Link2Forum|Topic=99219|Message=926652|LinkText=Batterie-Überwachung. 1xTäglich per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=101091|Message=945389|LinkText=Licht (Alarm) in einem bestimmten Zeitraum schalten}}&lt;br /&gt;
* {{Link2Forum|Topic=100949|Message=944284|LinkText=Über Dummy-Schalter ein Timer (EIN/AUS) aktivieren}}&lt;br /&gt;
* {{Link2Forum|Topic=103083|Message=967710|LinkText=Ladezeit von Akku ermitteln u. Steckdose entsprechend schalten}}&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31473</id>
		<title>MSwitch</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=MSwitch&amp;diff=31473"/>
		<updated>2019-11-01T19:55:51Z</updated>

		<summary type="html">&lt;p&gt;Maista: /* add event */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[MSwitch]] ist ein Hilfsmodul, welches das Event- und/oder zeitgesteuerte Schalten von mehreren Devices oder das Ausführen von benutzerdefinierten Befehlssequenzen erlaubt.&lt;br /&gt;
&lt;br /&gt;
Die Stärke bzw. das Unterscheidungsmerkmal dieses Moduls liegt in der Konfigurierbarkeit über ein Webinterface. Diese Konfiguration kann jederzeit geändert oder erweitert werden. &lt;br /&gt;
&lt;br /&gt;
Byte09: &#039;&#039;Die Grundidee zu MSwitch kam mir, weil ich bei der Arbeit mit FHEM für meinen Geschmack zu viele Module für die verschiedenen Aufgaben brauchte - zu allem Überfluss alle mit unterschiedlicher Syntax. Zwar ist DOIF hiervon ausgenommen (da hiermit wohl auch fast jede Aufgabe lösbar ist), aber ich konnte mich leider nicht daran gewöhnen und somit wurde jedes DOIF für mich zu einem echten Projekt. Was ich wollte war ein Modul, mit dem ich alles erledigen kann. Daher entschloss ich mich schon nach fast einem knappen Jahr FHEM-Nutzung mein eigenes Modul zu schreiben, welches diese Anforderung erfüllt. MSwitch beinhaltet die Funktionalität aller bisherigen Hilfsmodule wie z.B. Notify, Doif, Watchdog, Dummy,( ab Modulversion 2.2 auch Sequenz ) es lassen sich all deren Funktionen umsetzen.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;MSwitch wird permanent - vorrangig nach meinen Bedürfnissen - weiterentwickelt, gerne nehme ich aber auch Anregungen von anderen Nutzern auf.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|ModPurpose=MSwitch&lt;br /&gt;
|ModType=h&lt;br /&gt;
|ModForumArea=Automatisierung&lt;br /&gt;
|ModTechName=98_MSwitch.pm&lt;br /&gt;
|ModOwner=Byte09}}&lt;br /&gt;
&lt;br /&gt;
== Grundsätzliche Überlegungen ==&lt;br /&gt;
Um das Modul zu nutzen, muss man zuerst folgende Fragen beantworten:&lt;br /&gt;
&lt;br /&gt;
* Welches Gerät soll auslösen oder zu welcher Zeit soll eine Auslösung erfolgen.&lt;br /&gt;
: Dies ist der Trigger. Jedes Event aus dem Eventmonitor kann als Trigger dienen. Will man mehrere Geräte als gleichzeitige Auslöser betreiben, so muss das Device GLOBAL gewählt und die entsprechenden Geräte angegeben werden (dies erzeugt höhere Systemlast und ist nur im Expert-Modus verfügbar). Weiterhin kann auch zu fest definierten Zeiten, Zufallszeiten oder Intervallen, unabhängig von einem Trigger, geschaltet werden; auch eine Kombination beider Varianten ist möglich. Diese Einstellungen erfolgen im ersten Teil des Webinterfaces.&lt;br /&gt;
&lt;br /&gt;
* Welche Bedingungen sollen bei Auslösung erfüllt sein?&lt;br /&gt;
: Wenn diese Bedingungen erfüllt sind, werden Kommandos ausgelöst. Die Bedingungen werden im zweiten Teil des Webinterfaces eingegeben. Dabei unterscheidet das Modul zwischen zwei Kommando-Kanälen (cmd1 und cmd2) und den dazugehörigen Geräten.&lt;br /&gt;
&lt;br /&gt;
* Welche Kommandos sollen ausgelöst werden?&lt;br /&gt;
: Im dritten Teil des Webinterfaces werden dann die konkreten Kommandos eingegeben. Typischerweise wählt man dabei aus einer Liste der Kommandos aus, die die zugehörigen Geräte insgesamt aufweisen (also so, wie man auf den Geräteseiten selber Kommandos auswählt). Es gibt zudem ein so genanntes FreeCmd, das ein Geräteunabhängiges Kommando zulässt, beispielsweise reinen Perl-Code.&lt;br /&gt;
&lt;br /&gt;
* Welche weiteren Bedingungen sollen noch gelten?&lt;br /&gt;
: Hier sind Ereignisgesteuerte wie auch Zeitgesteuerte Bedingungen möglich. Diese Bedingungen werden auch in dem dritten Teil des Webinterfaces eingetragen. So sind Verzögerungen und Wiederholungen und weitere Bedingungen möglich.&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen, Installation und Grundbefehle ==&lt;br /&gt;
Das MSwitch-Modul ist ohne weitere Voraussetzungen nutzbar und wird derzeit in der Version 2.08 über FHEM Update verteilt. &lt;br /&gt;
&lt;br /&gt;
=== Definition und Einrichtung ===&lt;br /&gt;
Mit Hilfe von MSwitch kann man mehrere Devices gleichzeitig schalten. Diese Schaltungen befinden sich in zwei möglichen Zweigen bei MSwitch. Dabei unterscheidet man im Modul zwischen den beiden Kommandos cmd1 und cmd2. Die zu einem Kommando gehörenden Geräte werden wir auch Zweig nennen. Die einzelnen Devices jedes Zweiges können mit weiteren Schaltbedingungen versehen werden (zeit- oder ereignisgesteuert). &lt;br /&gt;
&lt;br /&gt;
Folgende Möglichkeiten zum definieren des MSwitch Devices stehen zur Verfügung:&lt;br /&gt;
:&amp;lt;code&amp;gt;define &amp;lt;name&amp;gt; MSwitch&amp;lt;/code&amp;gt;&lt;br /&gt;
Es wird ein leeres Device angelegt, das dann komplett über das Webinterface konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das define eines MSwitch Devices generiert lediglich eine &#039;leere Hülle&#039;. Alle relevante Einstellungen werden in Readings und/oder Hashes gespeichert. Daher stehen relevanten Daten &#039;&#039;nicht&#039;&#039; in der fhem.cfg! Vielmehr finden sich diese Daten in der Datei fhem.save (die Speicherung erfolgt durch den Befehl Fhemsave).&lt;br /&gt;
&lt;br /&gt;
=== set-Befehle ===&lt;br /&gt;
Es sind derzeit die folgenden set-Befehle implementiert.&lt;br /&gt;
&lt;br /&gt;
==== set active ====&lt;br /&gt;
Setzt das Device in den Status &#039;active&#039;.&lt;br /&gt;
&lt;br /&gt;
==== set inactive ====&lt;br /&gt;
Setzt das Device in den Status &#039;inactive&#039;, es werden keine Befehle mehr ausgeführt. Dieser Status entspricht dem Attribut &#039;disable&#039;, ist aber nicht mit dem roten Fragezeichen (fhem save) verbunden.&lt;br /&gt;
&lt;br /&gt;
==== set on/off [&amp;lt;parameter&amp;gt;]====&lt;br /&gt;
Setzt das Device in den Status &#039;on&#039; oder &#039;off&#039;. Alle Befehle der &#039;on/off-Zweige&#039; werden ausgeführt.&lt;br /&gt;
Optional kann den Befehlen &#039;on&#039; und &#039;off&#039; ein weiterer Parameter mit übergeben werden. Dieser wird im Reading &#039;Parameter&#039; hinterlegt und es kann sofort in &#039;Freecmds&#039; oder &#039;Conditions&#039; darauf zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
==== set reload_timer ====&lt;br /&gt;
Alle gesetzten Timer werden gelöscht und neu berechnet.&lt;br /&gt;
&lt;br /&gt;
==== set change_renamed &amp;lt;oldname&amp;gt; &amp;lt;newname&amp;gt; ====&lt;br /&gt;
Sollten sich Devicenammen im ausführenden Teil geändert habe (affected Devices, Conditions, etc.) so kann das MSwitch mit diesem Befehl angepasst werden, ohne alle Einstellungen neu einstellen zu müssen.&lt;br /&gt;
&lt;br /&gt;
==== set exec_cmd1 / set exec_cmd1 ID [&amp;lt;ID&amp;gt;] ====&lt;br /&gt;
Bewirkt das sofortige Ausführen des entsprechenden Befehlszweiges. Bei Angabe einer ID werden nur die Befehle mit der entsprechenden ID ausgeführt.&lt;br /&gt;
&lt;br /&gt;
==== set MSwitch_backup ====&lt;br /&gt;
Erstellt eine Backup-Datei aller MSwitch Devices unter ./fhem/MSwitch_backup.cfg.&lt;br /&gt;
&lt;br /&gt;
Daten dieser Datei können im Bedarfsfall für einzelne oder gleichzeitig alle MSwitch Devices wieder zurückgespielt (hergestellt) werden.&lt;br /&gt;
&lt;br /&gt;
==== set del_delays ====&lt;br /&gt;
Löscht alle anstehenden, verzögerten Befehle (delays).&lt;br /&gt;
&lt;br /&gt;
==== set reset_cmd_count:1,2 ====&lt;br /&gt;
Löscht das entsprechende EVT_CMD_COUNT - Reading (entspricht Rückstellung auf &#039;0&#039;).&lt;br /&gt;
&lt;br /&gt;
==== set fakeevent [&amp;lt;device&amp;gt;]:&amp;lt;reading&amp;gt;:&amp;lt;arg&amp;gt; ====&lt;br /&gt;
Beispiel: &amp;lt;device&amp;gt; fakeevent state:on&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ob der Name (&amp;lt;device&amp;gt;) angegeben werden muss, oder nicht, ist abhängig davon, ob auf ein einzelnes Device, oder GLOBAL getriggert wird. Bei GLOBALEN Triggern muss das Device mit angegeben werden. Wird auf ein Device getriggert, so wird das Device automatisch gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit diesem Befehl kann das MSwitch Device neu getriggert werden, indem hier ein Event &#039;gefaked&#039; wird. Das MSwitch Device reagiert dann so, als wäre dieses Event vom getriggerten Gerät generiert worden. &lt;br /&gt;
&lt;br /&gt;
Dieses kann nötig sein, um z.B. einen Watchdog zu realisieren, in dem es nötig ist, dass sich das MSwitch Device mit einem bestimmten Event selber neu triggert - ggf. mit einem entsprechenden Delay (affected Device muss dafür u.A. des MSwitch Device selber sein).&lt;br /&gt;
&lt;br /&gt;
Es wird hierbei KEIN echtes Event generiert welches das System beeinflusst, sondern ausschließlich ein MSwitch-Interner Befehl umgesetzt!&lt;br /&gt;
&lt;br /&gt;
Bei dem Einsatz dieser Möglichkeit sollte das Attribut &#039;MSwitch_Safemode&#039; UNBEDINGT aktiviert sein, da &#039;Experimente&#039; hier schnell in einer Endlosschleife enden können, die nur durch ein Reboot unterbrochen werden kann. &lt;br /&gt;
&lt;br /&gt;
Ggf. werde ich hier sogar eine entsprechende Änderung vornehmen, dass dieser Befehl nur zur Verfügung steht, wenn Safemode aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
=== get-Befehle ===&lt;br /&gt;
==== get show_timer [&amp;lt;show&amp;gt;&amp;lt;delete&amp;gt;] ====&lt;br /&gt;
;Show&lt;br /&gt;
:Zeigt alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren.&lt;br /&gt;
;Delete&lt;br /&gt;
:Löscht alle anstehenden (gesetzten) Timer des Devices, die aus zeitabhängigen oder verzögerten Schaltbefehlen resultieren. Schaltbefehle basierend auf rein zeitabhängigen Angaben werden neu berechnet und gesetzt.&lt;br /&gt;
&lt;br /&gt;
==== get restore_MSwitch_data [&amp;lt;this_device&amp;gt;&amp;lt;all_devices&amp;gt;] ====&lt;br /&gt;
;this_device&lt;br /&gt;
:Stellt die Daten des Devices aus der Backupdatei wieder her, sofern diese in der Backupdatei gefunden werden (gesucht wird hier nach dem Namen des Devices).&lt;br /&gt;
;all_devices&lt;br /&gt;
:Stellt die Daten aller MSwitch Devices wieder her, sofern diese in der Backupdatei vorhanden sind. Diese Aktion kann einige Zeit in Anspruch nehmen und wird daher im Hintergrund (nonblocking) ausgeführt. Nach Beendigung erfolgt eine Benachrichtigung.&lt;br /&gt;
&lt;br /&gt;
Die Devices sind nach einem Restore funktionsfähig. Empfohlen wird ein Neustart von FHEM.&lt;br /&gt;
&lt;br /&gt;
==== get_config ==== &lt;br /&gt;
Zeigt die Konfigurationsdatei des MSwitchdevices an; diese kann in dem Fenster editiert werden. Das sollte nur von erfahrenen Usern getan werden! Im Normalfall sollte das Device nur über die Weboberfläche konfiguriert werden und eine falsche Konfiguration kann hier zu einem FHEM Absturz führen.&lt;br /&gt;
&lt;br /&gt;
==== get_support_info ==== &lt;br /&gt;
Öffnet ein Fenster mit einer formatierten Ansicht aller Einstellungen des Devices. Bei Supportanfragen sollte dieses immer mit geposted werden.&lt;br /&gt;
&lt;br /&gt;
==== get_MSwitch_preconf ====&lt;br /&gt;
Lädt vorkonfigurierte MSwitch-Devices. Diese Option ist nur dann vorhanden, wenn das Aktualisieren dieser vorkonfigurierten Devices im FHEM Update aktiviert ist.&lt;br /&gt;
&lt;br /&gt;
Diese kann durch ein einmaliges Update erfolgen mit:&lt;br /&gt;
:&amp;lt;code&amp;gt;update all https://raw.githubusercontent.com/Byte009/MSwitch_Addons/master/controls_mswitchaddons.txt&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Webinterface ==&lt;br /&gt;
MSwitch wird im Wesentlichen über das Webinterface eingerichtet. Wählt man das folgende Attribut&lt;br /&gt;
:&amp;lt;code&amp;gt;attr &amp;lt;name&amp;gt; MSwitch_Help 1&amp;lt;/code&amp;gt;&lt;br /&gt;
so wird im Modul selber eine sehr umfangreiche Hilfe angezeigt. Über das gesamte Webinterface hinweg erscheinen kleine Fragezeichen, die man anklicken kann und die beschreiben, was in dem jeweiligen Textfeld sinnvollerweise einzugeben ist bzw. was das Modul an dieser Stelle erwartet.&lt;br /&gt;
&lt;br /&gt;
Das Webinterface besteht aus vier Teilen. Änderungen in jedem Abschnitt müssen in dem jeweiligen Teil bestätigt werden und auch nur diese werden gespeichert. Bevor ein weiterer Teil bearbeitet wird, sollten Änderungen gespeichert werden, sie gehen sonst verloren.&lt;br /&gt;
&lt;br /&gt;
=== Trigger device/time ===&lt;br /&gt;
==== Trigger Device ====&lt;br /&gt;
In diesem Feld wird das Device ausgewählt, dessen Events eine Aktion auslösen sollen. Dazu werden alle verfügbaren Devices in einem Dropdownfeld angeboten.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es eine Auswahl &#039;GLOBAL&#039;, wenn das Attribut &#039;MSwitch_Expert&#039; gesetzt ist. Bei Auswahl dieser Option werden &#039;&#039;&#039;alle&#039;&#039;&#039; von FHEM generierten Events durch das MSwitch Device weiterverarbeitet, eine weitere Begrenzung der aktivierenden Events kann (und sollte) dann in einem folgenden Eingabefeld erfolgen, um die Systemlast zu reduzieren.&lt;br /&gt;
&lt;br /&gt;
==== Trigger Device Global Whitelist ====&lt;br /&gt;
Dieses Feld ist nur verfügbar, wenn als Trigger &#039;GLOBAL&#039; gewählt wurde.&lt;br /&gt;
&lt;br /&gt;
Hier kann die Liste eingehender Events weiter eingeschränkt werden. Es handelt sich um eine Whitelist, d.h., wenn es keine Einträge gibt, werden Events aller Devices verarbeitet. Sobald ein oder mehrere Einträge gemacht werden, werden nur noch Events der hier benannten Devices verarbeitet. Als Angabe können hier Devices benannt werden oder ganze DeviceTypen (z.B. TYPE=FS20). Mehrere Angaben sind durch Komma zu trennen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:MSwitchWebinterface1.png|400px|thumb|right|Webinterface, oben]]&lt;br /&gt;
Im gezeigten Beispiel wurde GLOBAL gewählt, weil nicht ein einzelnes Device, sondern eine Kombination aus zwei Geräten auslösen soll. Es werden also alle Ereignisse betrachtet, wobei die Whitelist dann auf die Devices Schlafzimmer (ein Temperaturmessgerät) und Schlafzimmerfenster (ein [[HM-Sec-SCo Tür-Fensterkontakt, optisch|optischer Kontakt]]) einschränkt. &lt;br /&gt;
&lt;br /&gt;
==== Trigger time ==== &lt;br /&gt;
Es besteht die Möglichkeit, das Modul (neben den Events) zu festen Zeiten auszulösen. Dann wären in die leer stehenden Zeilen bei &amp;quot;at&amp;quot; entsprechende Termine einzutragen. Zeitangaben erfolgen durch [STUNDEN:MINUTEN|TAGE], wobei die Tage von 1-7 gezählt werden (1 steht für Montag, 7 für Sonntag usw.). &lt;br /&gt;
Mehrere Zeitvorgaben können direkt aneinandergereiht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [17:00|1][18:30|23] den Trigger montags um 17 Uhr auslösen und dienstags sowie mittwochs um 18:30 Uhr.&lt;br /&gt;
Bei [00:10*20:00-21:00] würde der Schaltbefehl von 21 Uhr bis 21 Uhr alle 10 Minuten ausgeführt. Bei [?20:00-21:00] würde der Schaltbefehl zu einem zufälligen Zeitpunkt zwischen 20 und 21 Uhr ausgeführt.  [20:00|$we] bedeutet, dass nur am Wochenende um 20:00 geschaltet wird.&lt;br /&gt;
&lt;br /&gt;
==== Trigger conditions ====&lt;br /&gt;
Hier kann die Angabe von Bedingungen erfolgen, die zusätzlich zu dem triggernden Device erfüllt sein müssen.&lt;br /&gt;
Diese Bedingungen sind eng an DOIF-Syntax angelehnt. Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich.&lt;br /&gt;
&lt;br /&gt;
Wird in diesem Feld keine Angabe gemacht, so erfolgt der Schaltvorgang nur durch das triggernde Device ohne weitere Bedingungen.&lt;br /&gt;
&lt;br /&gt;
;Zeitabhängigkeit&lt;br /&gt;
:[19:10-23:00] - Trigger des Devices erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
;Readingabhängige Trigger&lt;br /&gt;
:[Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Trigger des Device erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
:Werden Readings mit Strings abgefragt (on,off,etc.), ist statt des Gleichheitszeichens &amp;quot;=&amp;quot; der Operator &amp;quot;eq&amp;quot; zu nutzen, der String muss in Anführungszeichen &amp;quot;&amp;quot; gesetzt werden.&lt;br /&gt;
;mehrere Beispiele&lt;br /&gt;
:[19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
:[19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
:[10:00-11:00|13] - schaltet Montag und Mittwoch zwischen 10 Uhr und 11 Uhr.&lt;br /&gt;
:[{ sunset() }-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
:{ !$we } löst den Schaltvorgang nur Werktagen an aus.&lt;br /&gt;
:{ $we } löst den Schaltvorgang nur an Wochenenden, Feiertagen aus.&lt;br /&gt;
&lt;br /&gt;
Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (beispielsweise würde dann am Mittwoch noch der Schaltvorgang erfolgen, obwohl als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
Bedingungen in diesem Feld gelten nur für auslösende Trigger eines Devices und haben keinen Einfluss auf zeitgesteuerte Auslöser.&lt;br /&gt;
&lt;br /&gt;
=== Trigger details ===&lt;br /&gt;
[[Datei:MSwitchWebinterface2.png|600px|thumb|right|Webinterface, Mitte]]&lt;br /&gt;
Während im obigen Feld das Device ausgewählt  werden konnte, wird hier das Ereignis festgelegt. Das Eingabefeld besteht aus mehreren Einzelfeldern.&lt;br /&gt;
&lt;br /&gt;
Im abgebildeten Fall wird cmd1 ausgelöst, wenn der Zustand des Schlafzimmerfenster-Sensors meldet, dass das Fenster offen ist. Cmd2 wird ausgelöst, wenn die Temperatur des Schlafzimmersensors unter einen bestimmten Wert fallen wird.&lt;br /&gt;
&lt;br /&gt;
==== execute &#039;cmd1/cmd2&#039;  ====&lt;br /&gt;
Hier kann  aus einer vorbelegten Dropdownliste ausgewählt werden, welches ankommende Event den entsprechenden Befehlszweig auslösen soll. In dieser Liste werden bei entsprechender Einstellung alle ankommenden Events eines vorher definierten Devices gespeichert. In einem weiteren Feld (siehe unten) können Events manuell zugefügt werden.&lt;br /&gt;
&lt;br /&gt;
==== Save incomming events ====&lt;br /&gt;
Bei Aktivierung dieser Option werden alle ankommenden Events des oben definierten Devices (oder Global) gespeichert und in entsprechenden Dropdownlisten angeboten.&lt;br /&gt;
&lt;br /&gt;
Da hier doch erhebliche Datenmengen anfallen können (je nach Device) wird empfohlen, diese Option nach der Konfiguration des Devices zu deaktivieren.&lt;br /&gt;
&lt;br /&gt;
==== add event ====&lt;br /&gt;
Hier besteht die Möglichkeit, unabhängig von der Option, ankommende Events automatisch zu speichern. Manuell Events anzulegen, die in den Dropdownliste zur Auswahl angeboten werden, ohne das entsprechendes Event erst vom Device geliefert werden muss.&lt;br /&gt;
&lt;br /&gt;
Es können mehrere Events gleichzeitig eingegeben werden, eine Trennung erfolgt durch &amp;quot; , &amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Hier ist zu unterscheiden, ob das gewählte triggernde Device ein einfaches Device ist oder ob der Trigger &#039;GLOBAL&#039; ist.&lt;br /&gt;
Bei triggernden Devices können Events in folgendem Formaten zugefügt werden:&lt;br /&gt;
&lt;br /&gt;
- *                                                    - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:wert   (z.b. state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:*      (z.b. state:* )                       - Aktion erfolgt auf die Events &amp;quot;state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- reading:(wert1/wert2/wert3) (z.b. state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;state:left&amp;quot; oder &amp;quot;state:right&amp;quot; etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Falls auf &#039;GLOBALE&#039; Events getriggert wird, muss das auslösende Device vorangestellt werden:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
- *                                                           - Aktion erfolgt auf alle auftretende Events des entsprechenden Device&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:wert   (z.b. device:state:on )                      - Aktion erfolgt nur auf das Event &amp;quot;device:state:on&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:*      (z.b. device:state:* )                       - Aktion erfolgt auf die Events &amp;quot;device:state:(on,off,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
- device:reading:(wert1/wert2/wert3) (z.b. device:state:(left/right) - Aktion erfolgt nur auf Events &amp;quot;device:state:left&amp;quot; oder &amp;quot;devicestate:right&amp;quot; etc.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Device kann auch hier gegen &amp;quot;*&amp;quot; ersetzt werden (*:state:on). In diesem Fall erfolgt eine Aktion auf alle Events die z.B. &amp;quot;state:on&amp;quot; enthalten, egal welches Device triggert.&lt;br /&gt;
&lt;br /&gt;
==== test event ====&lt;br /&gt;
Dieses Feld wird angeboten, wenn entsprechende vom Triggerdevice gelieferte Events gespeichert wurden.&lt;br /&gt;
&lt;br /&gt;
Durch Auslösen dieser Funktion wird das Event simuliert und entsprechende definierte Aktionen ausgelöst. Diese Funktion dient ausschließlich zum Testen der eingestellten Konfiguration. Alle entsprechenden Befehle werden ausgeführt, als würde das Event real eintreffen.&lt;br /&gt;
&lt;br /&gt;
==== apply filter to saved events ====&lt;br /&gt;
Beschreibung folgt&lt;br /&gt;
&lt;br /&gt;
==== clear saved event ====&lt;br /&gt;
Es werden alle gespeicherten Events gelöscht.&lt;br /&gt;
&lt;br /&gt;
Ausnahme: Events, die als Trigger eingestellt sind, bleiben erhalten.&lt;br /&gt;
&lt;br /&gt;
=== Affected devices ===&lt;br /&gt;
[[Datei:MSwitch_Screen_5.png|mini|rechts|affected devices]]&lt;br /&gt;
Dieser Abschnitt beinhaltet die Auswahl der Devices, die auf ein Event reagieren sollen.&lt;br /&gt;
&lt;br /&gt;
In dem Auswahlfeld werden alle Devices angeboten, die eines der folgenden Kriterien erfüllen:&lt;br /&gt;
# Die Abfrage &amp;quot;set Device ?&amp;quot; liefert einen Befehlssatz&lt;br /&gt;
# Das Attribut &#039;webcmd&#039; des Devices enthält Einträge&lt;br /&gt;
# Das Attribut &#039;MSwitch_Activate_MSwitchcmds&#039; ist aktiviert und das Attribut &#039;MSwitchcmds&#039; des betreffenden Devices enthält einen Befehlssatz&lt;br /&gt;
&lt;br /&gt;
Einzige Ausnahme ist der erste Listeneintrag &#039;FreeCMD&#039;. Die Auswahl dieses Eintrages bietet später die Möglichkeit Befehle auszuführen, die nicht an ein Device gebunden sind. Der Code in einem FreeCmd kann entweder reiner FHEM-Code sein ( set device on ) oder reiner Perl-Code. Wenn es sich um reinen Perl-Code handelt, ist dieser in geschweifte Klammen zu setzen { Perl-Code }.&lt;br /&gt;
&lt;br /&gt;
=== Device actions ===&lt;br /&gt;
[[Datei:Webinterface3.png|mini|rechts|device_actions]]&lt;br /&gt;
Hier stellt man die auszuführenden Aktionen der eingestellten Devices ein. Im ersten Abschnitt oben befindet sich ein FreeCmd, mit dem beliebige Kommandos eingetragen werden können. Im abgebildeten Beispiel ist dies sogar selbst definierter Perl-Code (die Funktion DebianMail sendet eine Mail). &lt;br /&gt;
&lt;br /&gt;
==== MSwitch cmd1/cmd2:  ====&lt;br /&gt;
Man wählt den Befehl aus dem betreffenden Device aus. Bei freien Textfeldern (wie im Fall des FreeCmd) wird der Befehl eingegeben.&lt;br /&gt;
&lt;br /&gt;
Es werden alle verfügbaren Befehle des Devices zur Auswahl angeboten. Je nach Attribut-Einstellungen werden Einträge aus entsprechenden &#039;webcmds&amp;quot; oder &#039;MSwitchcmds&#039; einbezogen. In Abhängigkeit des Befehls stehen unter Umständen weitere Felder oder Widgets zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
05.04.2018 NEU: Auswahlfeld &#039;MSwitchtoggle&#039; -&amp;gt; Beschreibung wird noch ergänzt !&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 condition  ====&lt;br /&gt;
Mit diesem Feld kann die Ausführung des Befehls von weiteren Bedingungen abhängig gemacht werden. Bei der Abfrage von Readings nach Strings (on, off, etc.) ist statt &amp;quot;=&amp;quot; &amp;quot;eq&amp;quot; zu nutzen und der String muss in &amp;quot;x&amp;quot; gesetzt werden. Es ist auf korrekte Eingabe der Leerzeichen zu achten.&lt;br /&gt;
&lt;br /&gt;
#Zeitabhängiges schalten: [19:10-23:00] - Schaltbefehl erfolgt nur in angegebenem Zeitraum&lt;br /&gt;
#Readingabhängiges schalten [Devicename:Reading] =/&amp;gt;/&amp;lt; X oder [Devicename:Reading] eq &amp;quot;x&amp;quot; - Schaltbefehl erfolgt nur bei erfüllter Bedingung.&lt;br /&gt;
&lt;br /&gt;
Soll nur an bestimmten Wochentagen geschaltet werden, muss eine Zeitangabe gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise würde [10:00-11:00|13] den Schaltvorgang nur Montag und Mittwoch zwischen 10 Uhr und 11 Uhr auslösen. Hierbei zählen die Wochentage von 1-7 für Montag-Sonntag.&lt;br /&gt;
&lt;br /&gt;
Die Kombination mehrerer Bedingungen und Zeiten ist durch AND oder OR möglich:&lt;br /&gt;
* [19:10-23:00] AND [Devicename:Reading] = 10 - beide Bedingungen müssen erfüllt sein.&lt;br /&gt;
* [19:10-23:00] OR [Devicename:Reading] = 10 - eine der Bedingungen muss erfüllt sein.&lt;br /&gt;
* [{sunset()}-23:00] - von Sonnenuntergang bis 23:00 Uhr.&lt;br /&gt;
* { !$we } löst den Schaltvorgang nur Werktagen aus&lt;br /&gt;
* { $we } löst den Schaltvorgang nur Wochenenden, Feiertagen aus&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung:&#039;&#039;&#039; Bei Anwendung der geschweiften Klammern zur Einleitung eines Perl Ausdrucks ist unbedingt auf die Leerzeichen hinter und vor der Klammer zu achten.&lt;br /&gt;
&lt;br /&gt;
Überschreitet die Zeitangabe die Tagesgrenze (24:00 Uhr), so gelten die angegebenen Tage noch bis zum Ende der angegebenen Schaltzeit (zum Beispiel würde auch am Mittwoch noch der Schaltvorgang erfolgen, wenn als Tagesvorgabe Dienstag gesetzt wurde).&lt;br /&gt;
&lt;br /&gt;
; $EVENT:&lt;br /&gt;
: Die Variable EVENT enthält den auslösenden Trigger, d.h. es kann eine Reaktion in direkter Abhängigkeit zum auslösenden Trigger erfolgen.&lt;br /&gt;
&lt;br /&gt;
[$EVENT] eq &amp;quot;state:on&amp;quot; würde den Kommandozweig nur dann ausführen, wenn der auslösende Trigger &amp;quot;state:on&amp;quot; war. Wichtig ist dieses, wenn bei den Triggerdetails nicht schon auf ein bestimmtes Event getriggert wird, sondern hier durch die Nutzung eines Wildcards (*) auf alle Events getriggert wird, oder auf alle Events eines Readings z.B. (state:*).&lt;br /&gt;
&lt;br /&gt;
==== cmd1/cmd2 delay  ====&lt;br /&gt;
Ein Eintrag in diesem Feld führt zur verzögerten Ausführung des Befehls nach Eintreffen des Events. Dabei kann der Befehl ohne weitere Prüfung der Bedingung ausgelöst werden. Es ist aber auch möglich, dass die Bedingung bei Ausführung erneut geprüft wird. Die Zeitangabe muss im Format hh:mm:ss vorliegen.&lt;br /&gt;
&lt;br /&gt;
Statt einer unmittelbaren Zeitangabe kann hier auch ein Verweis auf ein Reading eines Devices erfolgen :&amp;lt;br&amp;gt;&lt;br /&gt;
[NAME.reading] des Devices -&amp;gt;z.B. [dummy.state]&lt;br /&gt;
&lt;br /&gt;
==== add action  ====&lt;br /&gt;
Mit diesem Button kann ein weiteres Eingabefeld für das entsprechende Device angelegt werden, um z.B. einen weiteren Befehl (ggf.) zeitverzögert auszuführen.&lt;br /&gt;
&lt;br /&gt;
==== delete this action  ====&lt;br /&gt;
Mit diesem Button wird der entsprechende Befehl für das Device gelöscht.&lt;br /&gt;
&lt;br /&gt;
==== check condition  ====&lt;br /&gt;
[[Datei:MSwitch_Screen_7.png|mini|rechts|check]]&lt;br /&gt;
Die angegebenen &#039;conditions&#039; werden in Zusammenhang mit ggf. ausgewählten Devices auf Syntax und Ergebnis geprüft. Es erfolgt eine Ausgabe des Prüfungsergebnisses.&lt;br /&gt;
&lt;br /&gt;
==== Repeat und Repeatdelay ====&lt;br /&gt;
Man kann mehrfache Wiederholungen erzwingen. Repeat gibt dabei an, wie oft das Kommando wiederholt wird (Anzahl). Repeatdelay gibt an, wie viel Sekunden zwischen einzelnen Wiederholungen liegen sollen.&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Folgende Attribute stehen zur Verfügung:&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Debug (0:1:2:3:4) ===&lt;br /&gt;
0 - Abgeschaltet&amp;lt;br&amp;gt;&lt;br /&gt;
1 - Schaltet Felder zum testen der Conditionstrings etc. an&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Alle ausgehenden Befehle werden nur simuliert und nicht ausgeführt. Es erfolgt eine Protokollierung in einer separaten Datei . Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
2 - Es erfolgt eine Protokollierung in einer separaten Datei . Diese wird direkt im Device angezeigt&amp;lt;br&amp;gt;&lt;br /&gt;
4 - erweiterte Debugfunktion (nur für Entwicklung - wechselnde Funktion )&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Expert (0:1) ===&lt;br /&gt;
In der Liste der möglichen Trigger erscheint das Selectfeld &#039;GLOBAL&#039;. Dieses ermöglicht das Setzen eines Triggers auf alle Events und damit nicht nur auf einzelne Devices. In einem weiteren Feld kann eine weitere Selektion der triggernden Events erfolgen.&lt;br /&gt;
&lt;br /&gt;
Es stehen weitere Felder &#039;Repeats&#039; und &#039;Repeatdelay in sec&#039; zur Verfügung. Eine hier getätigte Einstellung bewirkt X-fache Wiederholung von gesetzten Befehlen im Abstand der gesetzten Sekunden.&lt;br /&gt;
&lt;br /&gt;
Weiterhin kann über das Auswahlfeld &#039;priotity&#039; bei jedem &#039;affectes device&#039; die Reihenfolge beim abarbeiten der Befehle beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequenz &amp;lt;Suchmuster&amp;gt; ===&lt;br /&gt;
In diesem Attribut können ein oder mehrere Suchmuster angegeben werden ,die eine Schaltsequenz darstellen und vom Device erkannt werden.&lt;br /&gt;
&lt;br /&gt;
Die Angabe muss folgende Syntax haben:&lt;br /&gt;
:&amp;lt;code&amp;gt;Device1:reading1:event1 Device1:reading1:event1-2 Device1:reading1:event1-3/..../....&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mehrere Suchmuster müssen durch &amp;quot;/&amp;quot; getrennt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
:&amp;lt;code&amp;gt;Dummy:state:on Dummy:state:off Dummy:state:on&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erkennt das Device dieses Suchmuster in den Schaltvorgängen des Devices (Dummy), wird das Reading &amp;quot;SEQUENCE&amp;quot; auf &amp;quot;match&amp;quot; gesetzt, das Reading &amp;quot;SEQUENCE_NUMBER&amp;quot; auf die Nummer der gefundenen Sequenz, wenn es mehrere Suchmuster gibt. Beide Readings können in den &amp;quot;Conditions&amp;quot; eines Schaltbefehles abgefragt werden.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Sequence_time &amp;lt;Zeit in Sekunden&amp;gt; ===&lt;br /&gt;
Beinhaltet die Zeit in Sekunden, die es dauern darf, um eine Sequenz vollständig auszuführen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Extensions (0:1) ===&lt;br /&gt;
Es wird eine zusätzliche Schaltoption &#039;MSwitchToggle&#039; in den Geräten angeboten. Diese kann genutzt werden, wenn zuschaltende Geräte eine Togglefunktion nicht von Haus aus anbieten.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe muss in folgendem Format gemacht werden:&lt;br /&gt;
:&amp;lt;code&amp;gt;on/off/state/suchmuster1/suchmuster2&amp;lt;/code&amp;gt;, wobei die letzten drei Angaben optional sind.&lt;br /&gt;
&lt;br /&gt;
Funktion: Bei Ausführung des Befehls wird das Gerät &#039;on&#039; oder &#039;off&#039; geschaltet (on/off), Voraussetzung ist, dass der &#039;state&#039; dieses Gerätes auch den &#039;state on&#039; oder &#039;off&#039; annimmt. Sollte dieses nicht der Fall sein, so kann mit dem Feld &#039;state&#039; angegeben werden, in welchem Reading der aktuelle Status vorkommt und wie dieser lautet (suchmuster1/suchmuster2). Dieses &#039;state&#039; kann mehrere Angaben enthalten, das Vorkommen der Suchmuster ist aber Voraussetzung.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Delete_Delays (0:1) ===&lt;br /&gt;
Bewirkt das Löschen aller anstehende Timer (Delays) bei dem Auftreten eines erneuten, passenden Events. Bei der Option &#039;0&#039; bleiben bereits gesetzte Delays aus einem vorherigen, getriggertem Event erhalten und werden ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1)&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Devicecmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz liefern (bei Abfrage set DEVICE ?).&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_Webcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut Webcmd hinterlegt haben. Die in Webcmd hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten.&lt;br /&gt;
&lt;br /&gt;
Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Activate_MSwitchcmds (0:1) ===&lt;br /&gt;
Fügt jedem vorhandenen Device as Attribut &#039;MSwitchcmd&#039; hinzu.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Include_MSwitchcmds (0:1) ===&lt;br /&gt;
Bewirkt die Aufnahme aller Devices in die Auswahlliste &#039;Affected Devices&#039;, die einen eigenen Befehlssatz in dem Attribut MSwitchcmds hinterlegt haben. Die in MSwitchcmds hinterlegten &#039;Befehle&#039; werden in den Auswahlfeldern angeboten. Bei gesetzter Option (0) werden diese Devices nicht mehr berücksichtigt und somit nicht mehr Angeboten, wenn sie nicht zusätzlich einen eigenen Befehlssatz (set DEVICE ?) liefern.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (0), Einsatz nach Bedarf.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Lock_Quickedit (0:1) ===&lt;br /&gt;
Voreinstellung für die Auswahlliste &#039;Affected Devices&#039;. Bei der Option (1) ist diese voreingestellt gesperrt und kann nur über einen zusätzlichen Button geändert werden. Da es sich hier um ein Feld mit der Möglichkeit einer Mehrfacheingabe handelt handelt ist die Voreinstellung 1, um versehentliche nicht gewünschte Änderungen zu vermeiden (Auswahl einer Option ohne &#039;Strg&#039; bewirkt das löschen aller bereits gesetzten Optionen).&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (1).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay (0:10:20:30:60) ===&lt;br /&gt;
Diese Einstellung beeinflusst den Start von MSwitch nach einem FHEM Start. MSwitch ignoriert für die angegebene Zeit in Sekunden alle eingehenden Events um u.a. Startverzögerungen zu vermeiden. Bei nicht gesetztem Attribut gilt hier eine Zeit von 30 Sekunden. Diese sollte auch nur in Ausnahmefällen bzw. bei besonderem Bedarf geändert werden.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (30).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Ignore_Types ===&lt;br /&gt;
Beinhaltet eine Liste von Device&#039;&#039;typen&#039;&#039;, die in den Auswahllisten &#039;&#039;nicht&#039;&#039; dargestellt werden. Hier ist es sinnvoll, Devicetypen einzutragen, die in aller Regel nicht geschaltet werden oder nicht geschaltet werden können, um die Auswahllisten übersichtlicher zu halten. Einzelne Devicetypen sind durch Leerzeichen zu trennen.&lt;br /&gt;
&lt;br /&gt;
Voreinstellung: notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul.&lt;br /&gt;
&lt;br /&gt;
Eine Angabe kann hier in 2 Arten getätigt werden:&lt;br /&gt;
# eine Liste von devicetypen.&lt;br /&gt;
# Angabe einer devspec z.B. &amp;quot;TYPE=watchdog&amp;quot;. Hier ist zu beachten, dass in diesem Fall alle Geräte in die Ignoreliste einbezogen werden, die NICHT der devspec entsprechen. Weiterhin muss die devspec in Anführungszeichen gesetzt werden!&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Trigger_Filter ===&lt;br /&gt;
Beinhaltet eine Liste von Events, die bei eingehenden Events unberücksichtigt bleiben. Diese werde dann auch nicht gespeichert.&lt;br /&gt;
&lt;br /&gt;
Hier kann mit Wildcards (*) gearbeitet werden. Einzelne Events sind durch Komma &#039;,&#039; zu trennen.&lt;br /&gt;
&lt;br /&gt;
Empfohlene Einstellung (keine).&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Wait (sec)===&lt;br /&gt;
Bei gesetztem Attribut (Zeit in Sekunden) nimmt Das MSwitch Device für den eingestellten Zeitraum keine Befehle mehr entgegen und ignoriert eingehende Events&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Event_Id_Distributor ===&lt;br /&gt;
Dieses Attribut hat nur dann eine Funktion, wenn auch das Attribut &#039;MSwitchExpert&#039; auf &#039;1&#039; gesetzt ist.&lt;br /&gt;
Hier können verschiedene auslösende Events auf Aktionen mit angegebenen IDs umgeleitet werden.&lt;br /&gt;
&lt;br /&gt;
Sollte bei den &#039;trigger details :&#039; in einem Zweig ( cmd1 ) z.B. auf mehrere Events getriggert werden ( regex z.B. state:(on|off) ) so werden für beide Events jeweils der Zweig &#039;cmd1&#039; - alle  Aktionen ohneID - ausgeführt. Durch entsprechende Einträge kann für entsprechende Events auf eine Aktion umgeleitet werden , für die eine ID definierrtt ist. Die Syntax lautet:&lt;br /&gt;
:&amp;lt;code&amp;gt;state:on=&amp;gt;cmd1 ID 1,2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden bei auslösendem Event &#039;state:on&#039; nur die Aktionen aus cmd1 mit den IDs 1 und 2 ausgeführt. Mehrere Angaben sind durch new Line zu trennen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Selftrigger_always (0,1)===&lt;br /&gt;
(dieses Attribut steht ab Modulversion 2.5 zur Verfügung)&lt;br /&gt;
&lt;br /&gt;
Die Aktivierung dieses Attributes (1) bewirkt , dass alle SET Aktionen des Devices einen (internen) Event auslösen, auf die das Device selber reagiert. Diese Option kann zusätzlich zu einem vorhandenen Trigger aktiviert werden.&lt;br /&gt;
&lt;br /&gt;
Diese Events sind lediglich Deviceintern , d.H es werden keine Modulübergreifenden Events ausgelöst.&lt;br /&gt;
&lt;br /&gt;
Auftretende und auswertbare interne Events haben immer folgendes Format und können darüber augewertet weden.&lt;br /&gt;
&lt;br /&gt;
MSwitch_Self:aktion:wert &lt;br /&gt;
MSwitch_Self:pct:100&lt;br /&gt;
&lt;br /&gt;
Es werden nur interne Events für set-Aktionen ausgelöst , die im Attribut setlist hinterlegt sind.&lt;br /&gt;
&lt;br /&gt;
Als weitere Besonderheit unterliegen diese internen Events nicht dem &#039;wait&#039; Befehl/Attribut&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Mode (Notify,Full,Toggle,Dummy)===&lt;br /&gt;
Schaltet das Modul zwischen verschiedenen Modi um, mit entsprechend angepasster Weboberfläche.&lt;br /&gt;
&lt;br /&gt;
==== Notify ====&lt;br /&gt;
Das Device kann nicht manuell umgeschaltet werden, es gibt nur zwei ausführbare Zweige (execute &#039;cmd1&#039; commands und execute &#039;cmd2&#039; commands). Der Status des Devices wird nicht als &#039;on&#039; oder &#039;off&#039; angezeigt, sondern lediglich als &#039;active&#039;&lt;br /&gt;
&lt;br /&gt;
Dieser Mode ist am ehesten mit einem Notify zu Vergleichen.&lt;br /&gt;
==== Full ====&lt;br /&gt;
Es stehen alle Funktionen zur Verfügung.&lt;br /&gt;
==== Toggle ====&lt;br /&gt;
Sehr vereinfachter Mode. Es stehen keine verschiedenen Zweige zur Verfügung. Hier ist das Device manuell schaltbar und wird bei jedem definierten Event &#039;Umgeschaltet&#039;, entsprechend definierte Befehle für &#039;cmd1&#039; oder &#039;cmd2&#039; werden ausgeführt.&lt;br /&gt;
==== Dummy====&lt;br /&gt;
ACHTUNG: Funktionsänderung mit V2.61&lt;br /&gt;
&lt;br /&gt;
Der Mode &#039;Dummy&#039; ist ein eingeschränkter Modus. &lt;br /&gt;
Dieser bietet die Funktionalität eines Dummys kombiniert mit der Funktionalität eines Notifys und kann somit die gerne genutzte Kombination Dummy-Notify gegen ein Device ersetzen.&lt;br /&gt;
&lt;br /&gt;
Achtung: Devices die einmal in dem Modus &#039;Dummy&#039; gesetzt wurden können nicht wieder in einen anderen Mode geschaltet werden ! &lt;br /&gt;
&lt;br /&gt;
Der Dummy-Mode kann nur in einem neu angelegtem, leeren MSwitch aktiviert werden. Sobald ein angelegtes MSwitch einmal verändert wurde (modify trigger etc.) ist ein Umschalten nicht mehr möglich und die Option nicht mehr verfügbar.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Condition_Time (0,1)===&lt;br /&gt;
In der Grundeinstellung (0) werden für das zeitgesteuerte Schalten keine definierten Conditionen im Feld &#039;Trigger condition&#039; überprüft, sondern die Schaltbefehle werden in jedem Fall ausgeführt. Mit der Einstellung (1) wird diese Überprüfung auch für zeitgesteuerte Befehle zugeschaltet.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Time (HH:MM:SS-HH:MM:SS)===&lt;br /&gt;
Bei Aktivierung wird vor jedem Ausführen eines verzögerten Befehls ( Delay ) eine Zufallszeit generiert, die im Rahme der hier angegebenen Zeitspanne liegt. Auf diese Zufallszahl kann in den Delays zugegriffen werden, durch die Angabe &#039;[random]&#039; statt einer direkten Zeitangabe. Bei nicht gesetztem Attribut ergibt die Angabe von &#039; [random] &#039; hier immer &#039;00:00:00&#039;&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Random_Number ===&lt;br /&gt;
Bei Aktivierung dieses Attributes (der Inhalt kann einen beliebige Zahl sein) werden vom Device 2 Readings angelegt (Device:RandomNr) und (Device:RandomNr1). RandomNr wird vor jedem Ausführen eines Befehls aktualisiert und neu generiert, d.h wenn ein MSwitch Device mehrere Geräte schaltet, wird (auch in einem Durchgang) vor jedem Befehl dieses Reading neu gesetzt. RandomNr1 wird lediglich bei Ausführung des MSwitch Devices einmal neu gesetzt, d.h. nicht vor jedem Befehl der ausgeführt wird.&lt;br /&gt;
Die Readings werden mit einer Zufallszahl zwischen 0 und dem hier eingestellten Wert gesetzt.&lt;br /&gt;
&lt;br /&gt;
Auf diese Readings kann in jeder Condition mit z.B. &#039;[$NAME:ReadingNr1] = 1&#039; zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
D.h., das in der Condition angegebene Reading ( [$NAME:ReadingNr1] ) muss in diesem Fall den Wert 1 angenommen haben, ansonsten wird der Befehl nicht ausgeführt. &lt;br /&gt;
Der Befehl wird somit nur mit einer Wahrscheinlichkeit von 1 zu ( gesetzter Wert im Attr. ) ausgeführt.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Reset_EVT_CMD1(2)_COUNT ===&lt;br /&gt;
Bei Aktivierung dieses Attributes steht in den Readings das Reading &#039;EVT_CMD1_COUNT&#039; bzw. &#039;EVT_CMD2_COUNT&#039; zur Verfügung. Dieses kann in den Conditions genutzt werden, um z.B. nur bei jedem x-ten Eintreffen eines auslösenden Events einen Befehl auszuführen. Bei jedem Eintreffen eines gültigen Events werden die Zähler um 1 erhöht (für den jeweiligen Zweig). &lt;br /&gt;
Ist hier der Wert &#039;0&#039; eingetragen, wird der Zähler fortlaufend (endlos) erhöht. Wird ein Wert größer 0 eingetragen, wird der Zähler mit Erreichen dieses Wertes automatisch wieder auf Null gesetzt.&lt;br /&gt;
&lt;br /&gt;
Mit Löschen dieses Attributes werden die entsprechenden Readings ebenfalls gelöscht.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Safemode (0:1)===&lt;br /&gt;
Bietet einen (gewissen) Schutz vor falschen Konfigurationen und somit entstehenden Endlosschleifen.&lt;br /&gt;
Bei aktiviertem Attribut (1) erkennt das Modul Endlosschleifen eines Devices und beendet diese.&lt;br /&gt;
&lt;br /&gt;
In diesem Fall erfolgt ein Logeintrag und das Device wird per Attribut auf &#039;Disabled&#039; gesetzt.&lt;br /&gt;
Es wird ein letztes Event generiert, auf das reagiert werden kann:&lt;br /&gt;
:&amp;lt;code&amp;gt;2018-05-31 09:39:21 MSwitch &amp;lt;NAME&amp;gt; Safemode: on&amp;lt;/code&amp;gt;&lt;br /&gt;
Im Webinterface erfolgt bei betroffenem Device ein entsprechender Hinweis.&lt;br /&gt;
&lt;br /&gt;
In der Grundkonfiguration ist dieses Attribut nicht gesetzt, es empfiehlt sich aber, bei neuen (komplizierten) Devices, dieses - zumindest anfänglich - zu aktivieren.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Read_Log(0:1)===&lt;br /&gt;
Ermöglicht den Zugriff auf das Logfile als Trigger.&lt;br /&gt;
&lt;br /&gt;
Hier gibt es mehrere Konfigurationsmöglichkeiten:&lt;br /&gt;
* Bei aktiviertem Attribut enthält die Auswahl des Triggerdevices die Option &#039;LOGFILE&#039;. Bei dieser Auswahl werde alle Logeinträge erkannt und in ein internes Event umgewandelt, auf das regiert werden kann.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl &#039;GLOBAL&#039; im &#039;Trigger_Device&#039; wird auf ALLE Events und alle Logeinträge reagiert.&lt;br /&gt;
* bei aktiviertem Attribut und der Auswahl eines bestimmten Devices im &#039;Trigger_Device&#039; wird auf alle Events  und auf alle Logeinträge des gewählten Devices reagiert. Hier ist zu beachten, dass FHEM mir keine Möglichkeit bietet, wirklich herauszufinden, welches Device denn nun einen Logeintrag generiert hat. D.h., dieses wird vom Vorhandensein des Namens im Logeintrag abhängig gemacht und MSwitch reagiert nur dann auf einen Logeintrag, wenn der Name des Devices in diesem Eintrag vorhanden ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Help(0:1)===&lt;br /&gt;
Schaltet Hilfebuttons zu den einzelnen Eingabefeldern an oder aus.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Comments(0:1)===&lt;br /&gt;
Schaltet Kommentarfelder zu den einzelnen &#039;affected_devices an.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_generate_Events(0:1)===&lt;br /&gt;
Reduziert bei Einstellung &#039;1&#039; die vom MSwitch-Devices erzeugten Events auf ein absolutes Minimum. Insbesondere bei Verwendung von &#039;MSwitch_Read_Log&#039; zu empfehlen.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Startdelay ===&lt;br /&gt;
Bestimmt die Verzögerungszeit des MSwitches nach FHEM-Start in Sekunden. In diesem Zeitraum reagiert das ??Event??(Red: ist hier &amp;quot;Device&amp;quot; gemeint?) nicht auf Events. Die Vorgabe ist hier zehn Sekunden. Diese wird auch dann angenommen, wenn das Attribut nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
=== MSwitch_Inforoom ===&lt;br /&gt;
Mit diesem Attribut wird die Raumansicht eines mit dem Attribut bestimmten Raumes verändert. Dadurch sollen die wichtigsten Informationen aller MSwitch-Devices auf eine Seite dargestellt werden. Zur Nutzung sollten alle MSwitch-Devices (zusätzlich) in einen Raum sortiert werden und dieser Raum im Attribut eingestellt werden.&lt;br /&gt;
&lt;br /&gt;
Wichtig: Eine Änderung dieses Attributes bewirkt immer eine Änderung dieses Attributes in &#039;&#039;allen&#039;&#039; MSwitch devices: Es muss nur in einem Device gesetzt oder gelöscht werden um alle Devices zu erfassen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
MSwitch_Screen_1.png|Raumansicht des Raumes MSwitch mit gesetztem Attribut &#039;MSwitch&#039;&lt;br /&gt;
MSwitch_Screen_2.png|Raumansicht des Raumes MSwitch ohne gesetztes Attribut&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es werden folgende Informationen bereitgestellt:&lt;br /&gt;
* Infobutton zeigt den im Device gespeicherten Textes des Attributes &#039;comment&#039;&lt;br /&gt;
* Device und Events, die das Device triggern&lt;br /&gt;
* Zeiten, zu denen verschiedene Zweige des Devices ausgeführt werden&lt;br /&gt;
* Devices, die durch das MSwitch Device geschaltet werden&lt;br /&gt;
* State des Devices&lt;br /&gt;
&lt;br /&gt;
== Integrierte Funktionen ==&lt;br /&gt;
&lt;br /&gt;
=== Average ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
=== Tendency ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[TEND&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;Mindestwert&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[TEND2:countdown] &amp;gt; 2&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Es wird jeweils der Durchschnitt von 2 Wertepaaren gebildet. In diesem Fall werden die letzten 4 Werte herangezogen.&amp;lt;br&amp;gt;&lt;br /&gt;
Paar 1 = Aktueller und letzter Wert, Paar 2 = Die 2 vorherigen Werte.&amp;lt;br&amp;gt;&lt;br /&gt;
Bei TEND3 werden die letzten 6 Werte zur Paarbildung genutzt.&lt;br /&gt;
&lt;br /&gt;
Mindestwert:&lt;br /&gt;
Der Wertunterschied zwischen den Wertepaaren, der minimal erreicht sein muss, um eine Tendenz zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Rechenzeichen (&amp;gt;&amp;lt;):&lt;br /&gt;
Dieses ist hier nicht als Rechenzeichen zu werten, sonder als Tendenz-Anzeige. ( &amp;lt; es wird nach fallender Tendenz gesucht / &amp;gt; sucht nach steigender Tendenz).&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolgt einmalig bei Erkennung der gesuchten Tendenz.&lt;br /&gt;
Danach erfolgt keine Schaltung mehr, solange bis eine Tendenz-Umkehr erfolgt ist.&lt;br /&gt;
Erst dann erfolgt wieder eine Schaltung bei erneuter Tendenz-Umkehr in gesuchte Richtung.&lt;br /&gt;
&lt;br /&gt;
=== Difference ===&lt;br /&gt;
&lt;br /&gt;
Syntax:&lt;br /&gt;
[DIFF&amp;lt;wert&amp;gt;:&amp;lt;reading&amp;gt;] &amp;gt; &amp;lt;differenz&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
[DIFF2:countdown] &amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
Reading:&lt;br /&gt;
Entspricht dem getriggerten Reading.&lt;br /&gt;
&lt;br /&gt;
Wert:&lt;br /&gt;
Gespeicherter Wert (in diesem Fall der vorletzte).&lt;br /&gt;
&lt;br /&gt;
Differenz:&lt;br /&gt;
Geforderter Differenz zwischen aktuellem und vorletztem Wert.&lt;br /&gt;
&lt;br /&gt;
Schaltung erfolg wenn diese Bedingung &#039;wahr&#039; ist.&lt;br /&gt;
&lt;br /&gt;
Folgende Readings werden zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
DIFFERENCE (true/false) - Schaltbedingung erkannt ja/nein&lt;br /&gt;
&lt;br /&gt;
DIFFDIRECTION (up/down) - Richtung der erkannten Bedingung (steigend/fallend)&lt;br /&gt;
&lt;br /&gt;
=== Increase ===&lt;br /&gt;
Folgt&lt;br /&gt;
&lt;br /&gt;
== Tipps, Tricks, Kurzbeispiele ==&lt;br /&gt;
Wird stetig ergänzt .&lt;br /&gt;
&lt;br /&gt;
=== Blinken - Falls nicht im Device vorhanden ===&lt;br /&gt;
[[Datei:MSwitch MSwitchblink.png|center|704px]]&lt;br /&gt;
&amp;lt;br clear=all&amp;gt;&lt;br /&gt;
Lässt ein beliebiges Device 5 mal togglen, mit einem Intervall von 0.5 Sekunden (Blinkzeit somit 2,5 Sekunden)&amp;lt;br&amp;gt;&lt;br /&gt;
Die MSwitchtoggle-Funktion muss per ATTR aktiviert werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Die Repeatfunktion ist nur im Expertmode verfügbar, auch per ATTR einstellbar.&lt;br /&gt;
&lt;br /&gt;
=== Linearschalter ===&lt;br /&gt;
Umsetzung eines Linearschalters mit MSwitch.&lt;br /&gt;
&lt;br /&gt;
Eingang: Beliebiges Reading als numerischer Wert.&lt;br /&gt;
&lt;br /&gt;
Ausgang: Wird entsprechend Linear / oder umgekehrt Linear zum Eingang geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgend die Rawdefinition des MSwitchdevices und zweier Dummys (selbsterklärend)&lt;br /&gt;
&lt;br /&gt;
Alle Devices werden im Raum Lineartest angelegt, die Dummy müssen zuerst angelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod linearausgang dummy&lt;br /&gt;
attr linearausgang room Lineartest&lt;br /&gt;
attr linearausgang setList state:slider,0,1,100&lt;br /&gt;
attr linearausgang webCmd state&lt;br /&gt;
setstate linearausgang state 57&lt;br /&gt;
setstate linearausgang 2018-06-06 18:06:12 state state 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod lineareingang dummy&lt;br /&gt;
attr lineareingang room Lineartest&lt;br /&gt;
attr lineareingang setList state:slider,0,1,15000&lt;br /&gt;
attr lineareingang webCmd state&lt;br /&gt;
setstate lineareingang 6422&lt;br /&gt;
setstate lineareingang 2018-06-06 18:06:12 state 6422&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;defmod Linearschalter MSwitch lineareingang  # linearausgang FreeCmd&lt;br /&gt;
attr Linearschalter MSwitch_Debug 0&lt;br /&gt;
attr Linearschalter MSwitch_Delete_Delays 1&lt;br /&gt;
attr Linearschalter MSwitch_Expert 0&lt;br /&gt;
attr Linearschalter MSwitch_Extensions 0&lt;br /&gt;
attr Linearschalter MSwitch_Help 0&lt;br /&gt;
attr Linearschalter MSwitch_Ignore_Types notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
attr Linearschalter MSwitch_Include_Devicecmds 1&lt;br /&gt;
attr Linearschalter MSwitch_Include_MSwitchcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Include_Webcmds 0&lt;br /&gt;
attr Linearschalter MSwitch_Inforoom MSwitch&lt;br /&gt;
attr Linearschalter MSwitch_Lock_Quickedit 1&lt;br /&gt;
attr Linearschalter MSwitch_Mode Notify&lt;br /&gt;
attr Linearschalter room Lineartest&lt;br /&gt;
&lt;br /&gt;
setstate Linearschalter active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:03:50 .Device_Affected FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:04:35 .Device_Affected_Details FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 );;my $emin=0;;my $emax=15000;;my $amin=100;;my $amax=0;;$eingang = $emin if $eingang &amp;lt; $emin;;$eingang = $emax if $eingang &amp;gt; $emax;;my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin;;readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 );;},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter:to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 .Device_Events no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .First_init done&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_cmd_on *&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_condition &lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_off no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 .Trigger_on no_trigger&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 .Trigger_time &lt;br /&gt;
setstate Linearschalter 2018-06-04 18:24:21 .V_Check V 0.3&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVENT state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTFULL lineareingang:state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART1 lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART2 state&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 EVTPART3  6422&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 Exec_cmd set linearausgang state [Linearschalter:to_set]&lt;br /&gt;
setstate Linearschalter 2018-06-06 17:58:56 Trigger_device lineareingang&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:00:47 Trigger_log off&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 last_event state: 6422&lt;br /&gt;
setstate Linearschalter 2018-06-04 18:39:56 state active&lt;br /&gt;
setstate Linearschalter 2018-06-06 18:06:12 to_set 57&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
MSwitch -Configfile (bei Bedarf)&lt;br /&gt;
&amp;lt;pre&amp;gt;#V V1.54&lt;br /&gt;
#S .Device_Affected -&amp;gt; FreeCmd-AbsCmd1,FreeCmd-AbsCmd2,linearausgang-AbsCmd1&lt;br /&gt;
#S .Device_Affected_Details -&amp;gt; FreeCmd-AbsCmd1,cmd,cmd,{my $eingang =ReadingsVal( &amp;quot;lineareingang&amp;quot;## &amp;quot;state&amp;quot;## 0 )[S]my $emin=0[S]my $emax=15000[S]my $amin=100[S]my $amax=0[S]$eingang = $emin if $eingang &amp;lt; $emin[S]$eingang = $emax if $eingang &amp;gt; $emax[S]my $y= (($amax-$amin)/($emax-$emin)*($eingang-$emin))+$amin[S]readingsSingleUpdate( $hash## &amp;quot;to_set&amp;quot;## int ($y)## 1 )[S]},,delay1,delay1,000000,000000,,,0,0|FreeCmd-AbsCmd2,cmd,cmd,,,delay1,delay1,000000,000000,,,0,0|linearausgang-AbsCmd1,state,no_action,[Linearschalter.to_set],,delay1,delay1,000000,000000,,,0,0&lt;br /&gt;
#S .Device_Events -&amp;gt; no_trigger&lt;br /&gt;
#S .First_init -&amp;gt; done&lt;br /&gt;
#S .Trigger_Whitelist -&amp;gt; undef&lt;br /&gt;
#S .Trigger_cmd_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_cmd_on -&amp;gt; *&lt;br /&gt;
#S .Trigger_condition -&amp;gt; &lt;br /&gt;
#S .Trigger_off -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_on -&amp;gt; no_trigger&lt;br /&gt;
#S .Trigger_time -&amp;gt; &lt;br /&gt;
#S .V_Check -&amp;gt; V 0.3&lt;br /&gt;
#S Trigger_device -&amp;gt; lineareingang&lt;br /&gt;
#S Trigger_log -&amp;gt; off&lt;br /&gt;
#S last_event -&amp;gt; state: 6422&lt;br /&gt;
#S state -&amp;gt; active&lt;br /&gt;
#A MSwitch_Ignore_Types -&amp;gt; notify allowed at watchdog doif fhem2fhem telnet FileLog readingsGroup FHEMWEB autocreate eventtypes readingsproxy svg cul&lt;br /&gt;
#A MSwitch_Include_MSwitchcmds -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Debug -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Help -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Devicecmds -&amp;gt; 1&lt;br /&gt;
#A MSwitch_Extensions -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Include_Webcmds -&amp;gt; 0&lt;br /&gt;
#A room -&amp;gt; Lineartest&lt;br /&gt;
#A MSwitch_Inforoom -&amp;gt; MSwitch&lt;br /&gt;
#A MSwitch_Expert -&amp;gt; 0&lt;br /&gt;
#A MSwitch_Lock_Quickedit -&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Thread über das Modul im {{Link2Forum|Topic=86199|LinkText=FHEM Forum}}&lt;br /&gt;
* {{Link2Forum|Topic=100119|Message=936495|LinkText=Gäste-WLAN der Fritzbox auswerten und Login per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=86199|Message=930133|LinkText=Schalten von vier Kanälen mit einem MSwitch-Device}}&lt;br /&gt;
* {{Link2Forum|Topic=99219|Message=926652|LinkText=Batterie-Überwachung. 1xTäglich per Telegram senden}}&lt;br /&gt;
* {{Link2Forum|Topic=101091|Message=945389|LinkText=Licht (Alarm) in einem bestimmten Zeitraum schalten}}&lt;br /&gt;
* {{Link2Forum|Topic=100949|Message=944284|LinkText=Über Dummy-Schalter ein Timer (EIN/AUS) aktivieren}}&lt;br /&gt;
* {{Link2Forum|Topic=103083|Message=967710|LinkText=Ladezeit von Akku ermitteln u. Steckdose entsprechend schalten}}&lt;/div&gt;</summary>
		<author><name>Maista</name></author>
	</entry>
</feed>