<?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=Plin53177</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=Plin53177"/>
	<link rel="alternate" type="text/html" href="http://wiki.fhem.de/wiki/Spezial:Beitr%C3%A4ge/Plin53177"/>
	<updated>2026-04-10T21:06:10Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Solar-/PV-%C3%9Cbersicht&amp;diff=38213</id>
		<title>Solar-/PV-Übersicht</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Solar-/PV-%C3%9Cbersicht&amp;diff=38213"/>
		<updated>2023-03-25T08:10:36Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Angrenzende Themen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;float:right;margin-left:10px&amp;quot;&amp;gt;__TOC__&amp;lt;/div&amp;gt;&lt;br /&gt;
Die Seite [[Solar-/PV-Übersicht]] soll einen schnellen Einstieg in die für Solar-/Photovoltaik-Betreiber relevanten Seiten und Threads ermöglichen. Bitte bei Bedarf selbständig ergänzen.&lt;br /&gt;
&lt;br /&gt;
==Forum==&lt;br /&gt;
Der Forenbereich {{Link2Forum|Area=Solaranlagen}} enthält Themen rund um Solaranlagen zur Wärme- oder Stromgewinnung.&lt;br /&gt;
&lt;br /&gt;
Unter der Überschrift {{Link2Forum|Topic=116747|LinkText=&amp;quot;Frevel: Die Idee einheitlicher Devicenamen und Readings&amp;quot;}} findet gerade eine Diskussion zum Thema Namenskonventionen für Readings statt.&lt;br /&gt;
&lt;br /&gt;
== Allgemein ==&lt;br /&gt;
* [[Fotovoltaikanlage]]&lt;br /&gt;
* Viele Seiten der Kategorie [[:Kategorie:Energieerzeugungsmessung|Energieerzeugungsmessung]]&lt;br /&gt;
&lt;br /&gt;
==Wechselrichter==&lt;br /&gt;
===Kostal===&lt;br /&gt;
* [[KostalPiko]]&lt;br /&gt;
* [[Kostal Plenticore 10 Plus]]&lt;br /&gt;
&lt;br /&gt;
===SMA===&lt;br /&gt;
* [[SMAWechselrichter]]&lt;br /&gt;
&lt;br /&gt;
===Solar Edge===&lt;br /&gt;
* [[SolarEdge SE10k]]&lt;br /&gt;
&lt;br /&gt;
===Sunways===&lt;br /&gt;
* [[NT5000]]&lt;br /&gt;
&lt;br /&gt;
==Speicher==&lt;br /&gt;
* [[Sonnenspeicher]]&lt;br /&gt;
&lt;br /&gt;
==Monitoring/Auswertung==&lt;br /&gt;
* [[Enecsys Monitoring System]]&lt;br /&gt;
* [[SunnyHomeManager]]&lt;br /&gt;
* [[Datenbankgestützte Erstellung der Energiebilanz einer SMA PV-Anlage mit Überschusseinspeisung]]&lt;br /&gt;
* [[SolarLog]]&lt;br /&gt;
* [[SolarForecast - Solare Prognose (PV Erzeugung) und Verbrauchersteuerung]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Angrenzende Themen==&lt;br /&gt;
Verwandte Themen, &amp;quot;gern verwendete&amp;quot; oder erforderliche Module, etc.:&lt;br /&gt;
* [[ModbusAttr]]&lt;br /&gt;
* [[SMLUSB]]&lt;br /&gt;
* [[EBUS-ECMD]]&lt;br /&gt;
* [[Stromzähler auslesen]]&lt;br /&gt;
* Externer Link [https://www.photovoltaikforum.com/ Photovoltaik-Forum]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Solar-/PV-%C3%9Cbersicht&amp;diff=38212</id>
		<title>Solar-/PV-Übersicht</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Solar-/PV-%C3%9Cbersicht&amp;diff=38212"/>
		<updated>2023-03-25T08:05:38Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Monitoring/Auswertung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;float:right;margin-left:10px&amp;quot;&amp;gt;__TOC__&amp;lt;/div&amp;gt;&lt;br /&gt;
Die Seite [[Solar-/PV-Übersicht]] soll einen schnellen Einstieg in die für Solar-/Photovoltaik-Betreiber relevanten Seiten und Threads ermöglichen. Bitte bei Bedarf selbständig ergänzen.&lt;br /&gt;
&lt;br /&gt;
==Forum==&lt;br /&gt;
Der Forenbereich {{Link2Forum|Area=Solaranlagen}} enthält Themen rund um Solaranlagen zur Wärme- oder Stromgewinnung.&lt;br /&gt;
&lt;br /&gt;
Unter der Überschrift {{Link2Forum|Topic=116747|LinkText=&amp;quot;Frevel: Die Idee einheitlicher Devicenamen und Readings&amp;quot;}} findet gerade eine Diskussion zum Thema Namenskonventionen für Readings statt.&lt;br /&gt;
&lt;br /&gt;
== Allgemein ==&lt;br /&gt;
* [[Fotovoltaikanlage]]&lt;br /&gt;
* Viele Seiten der Kategorie [[:Kategorie:Energieerzeugungsmessung|Energieerzeugungsmessung]]&lt;br /&gt;
&lt;br /&gt;
==Wechselrichter==&lt;br /&gt;
===Kostal===&lt;br /&gt;
* [[KostalPiko]]&lt;br /&gt;
* [[Kostal Plenticore 10 Plus]]&lt;br /&gt;
&lt;br /&gt;
===SMA===&lt;br /&gt;
* [[SMAWechselrichter]]&lt;br /&gt;
&lt;br /&gt;
===Solar Edge===&lt;br /&gt;
* [[SolarEdge SE10k]]&lt;br /&gt;
&lt;br /&gt;
===Sunways===&lt;br /&gt;
* [[NT5000]]&lt;br /&gt;
&lt;br /&gt;
==Speicher==&lt;br /&gt;
* [[Sonnenspeicher]]&lt;br /&gt;
&lt;br /&gt;
==Monitoring/Auswertung==&lt;br /&gt;
* [[Enecsys Monitoring System]]&lt;br /&gt;
* [[SunnyHomeManager]]&lt;br /&gt;
* [[Datenbankgestützte Erstellung der Energiebilanz einer SMA PV-Anlage mit Überschusseinspeisung]]&lt;br /&gt;
* [[SolarLog]]&lt;br /&gt;
* [[SolarForecast - Solare Prognose (PV Erzeugung) und Verbrauchersteuerung]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Angrenzende Themen==&lt;br /&gt;
Verwandte Themen, &amp;quot;gern verwendete&amp;quot; oder erforderliche Module, etc.:&lt;br /&gt;
* [[ModbusAttr]]&lt;br /&gt;
* [[SMLUSB]]&lt;br /&gt;
* Externer Link [https://www.photovoltaikforum.com/ Photovoltaik-Forum]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Wertpapieranzeige&amp;diff=35826</id>
		<title>Wertpapieranzeige</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Wertpapieranzeige&amp;diff=35826"/>
		<updated>2021-06-17T08:45:48Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Voraussetzungen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Der [[{{PAGENAME}}|Artikel &amp;quot;Wertpapieranzeige&amp;quot;]] beschreibt das Vorgehen zur Erzeugung einer komfortablen Anzeige verschiedener Wertpapiere in einer Liste auf Basis des Modules 98_STOCKQUOTES.pm&lt;br /&gt;
== Ergebnis ==&lt;br /&gt;
&#039;&#039;Natürlich&#039;&#039; habe ich hier die wirklichen Zahlen unkenntlich gemacht (pah, 9.1.2021)&lt;br /&gt;
&lt;br /&gt;
[[File:Depot.png|800px]]&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
Die Einrichtung eines Depots mit dem Modul 98 STOCKQUOTES wird hier [[STOCKQUOTES]] beschrieben. &lt;br /&gt;
&lt;br /&gt;
Für das folgende nehmen wir an, dass in dem Depot verschiedene Teildepots mit unterschiedlichen Währungen vorhanden sind, z.B. &#039;&#039;Depot2_EUR&#039;&#039; für Euro, &#039;&#039;Depot2_GBP&#039;&#039; für britische Pfund. &lt;br /&gt;
&lt;br /&gt;
Für jede Fremdwährung (z.B. GBP) muss ferner irgendein Device existieren (z.B. als Dummy), in welchem der Umrechnungskurs steht und per Perl-Funktion&lt;br /&gt;
 Value(&amp;quot;EUR_GBP&amp;quot;)&lt;br /&gt;
(bzw. entsprechend für andere Währungen) abgefragt werden kann. Diese Abfrage wird für die Formatierung benötigt und muss ggf. angepasst werden.&lt;br /&gt;
&lt;br /&gt;
== readingsGroup ==&lt;br /&gt;
Zunächst wird die readingsGroup definiert, dabei gibt es zwei(!) Zeilen für jedes Teildepot in einer anderen Währung:&lt;br /&gt;
 define Depot2_Detail readingsgroup &amp;lt; &amp;gt;,&amp;lt;Symbol&amp;gt;,&amp;lt;Stock&amp;gt;,&amp;lt;Value&amp;gt;,&amp;lt;Change_Rel&amp;gt;,&amp;lt;Change_Abs&amp;gt;,&amp;lt;Trend&amp;gt;,&amp;lt;Rate&amp;gt;,&amp;lt;Count&amp;gt;,&amp;lt;Cur&amp;gt; &lt;br /&gt;
 Depot2_EUR:depot_cur_value_total,depot_p_change_total,depot_value_diff_total,depot_buy_value_total:t&lt;br /&gt;
 Depot2_EUR:@2,&amp;lt;#1&amp;gt;,(.*)_name,#1_d_cur_value_total,#1_d_p_change_total,#1_d_value_diff_total,#1_close,#1_last,#1_d_stockcount&lt;br /&gt;
 Depot2_USD:depot_cur_value_total,depot_p_change_total,depot_value_diff_total,depot_buy_value_total:t&lt;br /&gt;
 Depot2_USD:@2,&amp;lt;#1&amp;gt;,(.*)_name,#1_d_cur_value_total,#1_d_p_change_total,#1_d_value_diff_total,#1_close,#1_last,#1_d_stockcount,#1_currency&lt;br /&gt;
 Depot2_SEK:depot_cur_value_total,depot_p_change_total,depot_value_diff_total,depot_buy_value_total:t&lt;br /&gt;
 Depot2_SEK:@2,&amp;lt;#1&amp;gt;,(.*)_name,#1_d_cur_value_total,#1_d_p_change_total,#1_d_value_diff_total,#1_close,#1_last,#1_d_stockcount,#1_currency &lt;br /&gt;
 Depot2_GBP:depot_cur_value_total,depot_p_change_total,depot_value_diff_total,depot_buy_value_total:t&lt;br /&gt;
 Depot2_GBP:@2,&amp;lt;#1&amp;gt;,(.*)_name,#1_d_cur_value_total,#1_d_p_change_total,#1_d_value_diff_total,#1_close,#1_last,#1_d_stockcount,#1_currency&lt;br /&gt;
Die Kopfzeilen und -spalten werden mit breiteren Tabellenspalten versehen und hervorgehoben:&lt;br /&gt;
 attr Depot2_Detail valueColumns { &#039;depot_cur_value_total&#039; =&amp;gt; &#039;colspan=&amp;quot;2&amp;quot;&#039;,&#039;depot_buy_value_total&#039; =&amp;gt; &#039;colspan=&amp;quot;4&amp;quot;&#039;}&lt;br /&gt;
 attr Depot2_Detail nameStyle style=&amp;quot;font-weight:bold&amp;quot;&lt;br /&gt;
=== Formatierungen ===&lt;br /&gt;
Als Nächstes werden die Einzelwerte formatiert und bei Fremdwährungen umgerechnet. Dabei kann man auf spezielle Eigenschaften der Teildepots eingehen - beispielsweise wird im Nachfolgenden der &#039;&#039;_close&#039;&#039;-Wert durch den Kursprovider nicht für eine Aktie, sondern für 100 Aktien angegeben und muss entsprechend herunterskaliert werden.&lt;br /&gt;
 attr Depot2_Detail valueFormat 	&lt;br /&gt;
 {if($READING =~ /.*name/){$VALUE=~/.*\((.*)\).*/;;$VALUE=$1}&lt;br /&gt;
 elsif($READING =~ /.*((cur_value_total)|(value_diff_total))/ &amp;amp;&amp;amp; $DEVICE eq &amp;quot;Depot2_EUR&amp;quot;){$VALUE.=&amp;quot;€&amp;quot;}&lt;br /&gt;
 elsif($READING =~ /.*((cur_value_total)|(value_diff_total))/ &amp;amp;&amp;amp; $DEVICE =~ /Depot2_(.*)/ ){$VALUE=(int($VALUE/Value(&amp;quot;EUR_&amp;quot;.$1)*100)/100).&amp;quot;€&amp;quot;}&lt;br /&gt;
 elsif($READING =~ /.*p_change_total/){$VALUE=(int($VALUE*10)/10).&amp;quot;%&amp;quot;}&lt;br /&gt;
 elsif($READING =~ /(.*)_close/ &amp;amp;&amp;amp; $DEVICE eq &amp;quot;Depot2_GBP&amp;quot;){my $tr=(100*ReadingsVal(&amp;quot;$DEVICE&amp;quot;,$1.&amp;quot;_last&amp;quot;,1)/ReadingsVal(&amp;quot;$DEVICE&amp;quot;,$1.&amp;quot;_close&amp;quot;,1)-1);(int(1000*$tr)/10).&amp;quot;%% &amp;quot;.(($tr&amp;gt;0.01)?&amp;quot;🢁&amp;quot;:(($tr&amp;gt;0.001)?&amp;quot;🢅&amp;quot;:(($tr&amp;gt;-0.001)?&amp;quot;🢂&amp;quot;:(($tr&amp;gt;-0.01)?&amp;quot;🢆&amp;quot;:&amp;quot;🢃&amp;quot;)))) }&lt;br /&gt;
 elsif($READING =~ /(.*)_close/){my $tr=(ReadingsVal(&amp;quot;$DEVICE&amp;quot;,$1.&amp;quot;_last&amp;quot;,1)/ReadingsVal(&amp;quot;$DEVICE&amp;quot;,$1.&amp;quot;_close&amp;quot;,1)-1);(int(1000*$tr)/10).&amp;quot;%% &amp;quot;.(($tr&amp;gt;0.01)?&amp;quot;🢁&amp;quot;:(($tr&amp;gt;0.001)?&amp;quot;🢅&amp;quot;:(($tr&amp;gt;-0.001)?&amp;quot;🢂&amp;quot;:(($tr&amp;gt;-0.01)?&amp;quot;🢆&amp;quot;:&amp;quot;🢃&amp;quot;)))) }}&lt;br /&gt;
=== Farben ===&lt;br /&gt;
Im letzten Schritt werden jetzt noch Farben hinzugegeben 	&lt;br /&gt;
 attr Depot_Detail valueStyle &lt;br /&gt;
 {if($READING =~ /depot.*/ ){&#039;style=&amp;quot;background-color:#aaaaff;font-weight:bold;text-align:right&amp;quot;&#039;}&lt;br /&gt;
 elsif($READING =~ /.*cur_value_total/){&#039;style=&amp;quot;text-align:right&amp;quot;&#039;}&lt;br /&gt;
 elsif($READING =~ /.*((p_change_total)|(d_value_diff_total))/ &amp;amp;&amp;amp; $VALUE&amp;lt;0){&#039;style=&amp;quot;color:red;text-align:right&amp;quot;&#039;}&lt;br /&gt;
 elsif($READING =~ /.*((p_change_total)|(d_value_diff_total))/ &amp;amp;&amp;amp; $VALUE&amp;gt;0){&#039;style=&amp;quot;color:green;text-align:right&amp;quot;&#039;}&lt;br /&gt;
 elsif($READING =~ /(.*)_close/ &amp;amp;&amp;amp; $DEVICE eq &amp;quot;Depot2_GBP&amp;quot;){my $tr=(100*ReadingsVal(&amp;quot;$DEVICE&amp;quot;,$1.&amp;quot;_last&amp;quot;,1)/ReadingsVal(&amp;quot;$DEVICE&amp;quot;,$1.&amp;quot;_close&amp;quot;,1)-1);&#039;style=&amp;quot;text-align:right;color:&#039;. (($tr&amp;gt;0.01)?&#039;green&amp;quot;&#039;:(($tr&amp;gt;0.001)?&#039;#aaff44&amp;quot;&#039;:(($tr&amp;gt;-0.001)?&#039;black&amp;quot;&#039;:(($tr&amp;gt;-0.01)?&#039;#ffdd88&amp;quot;&#039;:&#039;red&amp;quot;&#039;)))) }&lt;br /&gt;
 elsif($READING =~ /(.*)_close/){my $tr=(ReadingsVal(&amp;quot;$DEVICE&amp;quot;,$1.&amp;quot;_last&amp;quot;,1)/ReadingsVal(&amp;quot;$DEVICE&amp;quot;,$1.&amp;quot;_close&amp;quot;,1)-1);&#039;style=&amp;quot;text-align:right;color:&#039;.(($tr&amp;gt;0.01)?&#039;green&amp;quot;&#039;:(($tr&amp;gt;0.001)?&#039;#aaff44&amp;quot;&#039;:(($tr&amp;gt;-0.001)?&#039;black&amp;quot;&#039;:(($tr&amp;gt;-0.01)?&#039;#ffdd88&amp;quot;&#039;:&#039;red&amp;quot;&#039;)))) }}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Solar-/PV-%C3%9Cbersicht&amp;diff=34441</id>
		<title>Solar-/PV-Übersicht</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Solar-/PV-%C3%9Cbersicht&amp;diff=34441"/>
		<updated>2020-12-22T20:01:26Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Forum */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;float:right;margin-left:10px&amp;quot;&amp;gt;__TOC__&amp;lt;/div&amp;gt;&lt;br /&gt;
Die Seite [[Solar-/PV-Übersicht]] soll einen schnellen Einstieg in die für Solar-/Photovoltaik-Betreiber relevanten Seiten und Threads ermöglichen. Bitte bei Bedarf selbständig ergänzen.&lt;br /&gt;
&lt;br /&gt;
==Forum==&lt;br /&gt;
Der Forenbereich {{Link2Forum|Area=Solaranlagen}} enthält Themen rund um Solaranlagen zur Wärme- oder Stromgewinnung&lt;br /&gt;
&lt;br /&gt;
Unter &amp;quot;[https://forum.fhem.de/index.php/topic,116747.0.html Frevel: Die Idee einheitlicher Devicenamen und Readings]&amp;quot; findet gerade eine Diskussion zum Thema Namenskonventionen für Readings statt ..&lt;br /&gt;
&lt;br /&gt;
== Allgemein ==&lt;br /&gt;
* [[Fotovoltaikanlage]]&lt;br /&gt;
* Viele Seiten der Kategorie [[:Kategorie:Energieerzeugungsmessung|Energieerzeugungsmessung]]&lt;br /&gt;
&lt;br /&gt;
==Wechselrichter==&lt;br /&gt;
===Kostal===&lt;br /&gt;
* [[KostalPiko]]&lt;br /&gt;
* [[Kostal Plenticore 10 Plus]]&lt;br /&gt;
&lt;br /&gt;
===SMA===&lt;br /&gt;
* [[SMAWechselrichter]]&lt;br /&gt;
&lt;br /&gt;
===Solar Edge===&lt;br /&gt;
* [[SolarEdge SE10k]]&lt;br /&gt;
&lt;br /&gt;
===Sunways===&lt;br /&gt;
* [[NT5000]]&lt;br /&gt;
&lt;br /&gt;
==Speicher==&lt;br /&gt;
* [[Sonnenspeicher]]&lt;br /&gt;
&lt;br /&gt;
==Monitoring/Auswertung==&lt;br /&gt;
* [[Enecsys Monitoring System]]&lt;br /&gt;
* [[SunnyHomeManager]]&lt;br /&gt;
* [[Datenbankgestützte Erstellung der Energiebilanz einer SMA PV-Anlage mit Überschusseinspeisung]]&lt;br /&gt;
* [[SolarLog]]&lt;br /&gt;
&lt;br /&gt;
==Angrenzende Themen==&lt;br /&gt;
Verwandte Themen, &amp;quot;gern verwendete&amp;quot; oder erforderliche Module, etc.:&lt;br /&gt;
* [[ModbusAttr]]&lt;br /&gt;
* [[SMLUSB]]&lt;br /&gt;
* Externer Link [https://www.photovoltaikforum.com/ Photovoltaik-Forum]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Grafana&amp;diff=34415</id>
		<title>Grafana</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Grafana&amp;diff=34415"/>
		<updated>2020-12-18T13:54:39Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* MySQL-Queries */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Randnotiz|RNText=Grafana beschreibt sich als &amp;quot;The open platform for beautiful analytics and monitoring&amp;quot;.&lt;br /&gt;
Eine Live Demo zum Erkunden findet man im Internet unter  [http://play.grafana.org play.grafana.org]}}&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Die [[Grafana]]-Software stellt einen Server zur Verfügung, mit dem Zeitreihen von Zahlenwerten auf sehr handliche Weise dargestellt und manipuliert werden können. Die Auswahl bestimmter Zeitfenster, das Anlegen von Dashboards und die Gestaltung der Achsen (Minimum. Maximum) ist so sehr einfach möglich. Zudem gibt es verschiedene Paneltypen, die neben dem klassischen Chart (Line / Bar / Point) auch Pie Charts oder Tabellen beinhalten. Seit November 2017 kann Grafana  mit MySQL umgehen, was eine Einbindung in FHEM (via DBLog) ermöglicht. Die Benutzeroberfläche lädt sehr schnell und ist auf vielen Geräten flüssig und einfach zu bedienen.&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
Hier sind mehrere Schritte (einmalig) durchzuführen. Für Grafana muss ein eigener Server installiert werden und für die Grafiken müssen MySQL-Queries angelegt werden. &lt;br /&gt;
&lt;br /&gt;
=== Installation und Einrichtung einer DBLog Instanz mit MySQL ===&lt;br /&gt;
Details sind auf der Seite [[DbLog#Beispiel:_Anlegen_und_Nutzung_einer_Mysql-Datenbank|Anlegen einer MySQL_Datenbank]] beschrieben. &lt;br /&gt;
&lt;br /&gt;
Wenn schon eine Datenbank angelegt wurde und man Daten umziehen muss, helfen andere Einträge weiter.&lt;br /&gt;
Sollen zum Beispiel Altdaten aus SQLite gesichert und wieder in MySQL eingespielt werden, [[DbRep - Reporting und Management von DbLog-Datenbankinhalten#Datensätze (Devices) von einer Datenbank in eine andere umziehen (Export/Import)|hilft dieser Eintrag]]. Dieses Beispiel sichert nur Logdaten für ein einzelnes Gerät und nicht für alles aus der DB. Das lässt sich aber problemlos anpassen, indem man das Attribut device in der DBRep Instanz nicht belegt.&lt;br /&gt;
&lt;br /&gt;
Ein Umstieg von Filelog auf DBLog geht ebenfalls. Sollen Altdaten aus den Filelogs übertragen werden, {{Link2Forum|Topic=66383|LinkText=hilft dieser Thread}}.&lt;br /&gt;
&lt;br /&gt;
=== Installation des Grafana Servers ===&lt;br /&gt;
Es gibt [https://grafana.com/grafana/download einen offiziellen Download]. Der ist nicht ganz unproblematisch, und will man auf einem Raspberry Pi installieren, sollten eher vorkompilierte Pakete genutzt werden. Sie sind [https://github.com/fg2it/grafana-on-raspberry/releases unter diesem Link] zu finden.&lt;br /&gt;
&lt;br /&gt;
Damit Grafana automatisch mit dem System startet, muss der Grafana Server noch aktiviert werden. Bei Verwendung von Systemd wäre das mit folgendem Befehl zu erledigen: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 sudo /bin/systemctl enable grafana-server&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Im Grafana Webinterface muss dann eine neue Datasource vom Typ MySQL angelegt werden. Die Daten der FHEM-MYSQL Datenbank eintragen (Port/User/Passwort).&lt;br /&gt;
&lt;br /&gt;
Grafana lauscht per default auf Port 3000. Dies kann ein Problem sein, falls man Alexa mit Custom Skill nutzt. Dieser Dienst belegt ebenfalls schon Port 3000.&lt;br /&gt;
In dem Fall mit &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 sudo nano /etc/grafana/grafana.ini &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
und die Konfiguration anpassen:&lt;br /&gt;
:&amp;lt;code&amp;gt;;http_port = 3000&amp;lt;/code&amp;gt;&lt;br /&gt;
Hier den führenden Semicolon entfernen und den Port entsprechend abändern. Zuletzt ist die Datenbank auszuwählen, in der die Daten von FHEM abgelegt sind (grafana greift standardmäßig auf eine Datenbank mit dem Namen grafana zurück).&lt;br /&gt;
&lt;br /&gt;
== Erstellen von Grafiken ==&lt;br /&gt;
=== MySQL-Queries ===&lt;br /&gt;
Zeitreihen werden in Grafana durch MySQL-Queries angelegt. Jede Zeitreihe benötigt dabei einen eigenen Query. Grafana legt dabei einen Musterquery an, bei dem drei Werte geändert werden müssen. &lt;br /&gt;
[[Datei:Grafana_Query_anlegen.png|200px|thumb|right|Query anlegen]]  &lt;br /&gt;
&lt;br /&gt;
Man klickt im Dashboard von Grafana auf AddRow. Durch einen Klick auf den Titel der neuen Grafik erscheint ein Menü (&amp;quot;View&amp;quot;, &amp;quot;Edit&amp;quot;, &amp;quot;Share&amp;quot;) und wählt Edit. Dann wählt man die FHEM-Datenbank aus, siehe Screenshot. Eine Musterabfrage sieht wie folgt aus:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
 SELECT&lt;br /&gt;
  UNIX_TIMESTAMP(&amp;lt; time &amp;gt;) as time_sec,&lt;br /&gt;
  &amp;lt; column &amp;gt; as value,&lt;br /&gt;
  &amp;lt; name &amp;gt; as metric  &lt;br /&gt;
  FROM &amp;lt; table name &amp;gt;   &lt;br /&gt;
  WHERE $__timeFilter(time_column)   &lt;br /&gt;
  ORDER BY &amp;lt; time &amp;gt; ASC&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Grafana benötigt in diesem Query mindestens drei Spalten mit der richtigen Benennung, die durch &amp;lt;&amp;gt;-Klammern vorgezeichnet sind.&lt;br /&gt;
* time_sec muss Zeitwerte im UNIX-Timestamp Format (Sekunden seit 01.01.1970) enthalten. Meist wählt man für &amp;lt; time &amp;gt; daher den TIMESTAMP Eintrag aus der Datenbank.&lt;br /&gt;
* value muss Werte für die Y-Achse liefern, welche den Zeitstempeln aus time_sec zuzuordnen sind. Meist wählt man für &amp;lt; column &amp;gt; daher den VALUE Eintrag aus der Datenbank.&lt;br /&gt;
* metric ist der Text, der für die Kurve in der Legende angezeigt wird. Daher ist &amp;lt; name &amp;gt; frei wählbar.&lt;br /&gt;
&lt;br /&gt;
Die Namen der einzelnen Spalten werden durch FHEM selbst vergeben. Man muss also bei der Verwendung der Queries herausfinden, wie die Werte intern gespeichert werden. Das klingt schwerer als es ist, weil sich FHEM dabei an Konventionen hält, die leicht geraten werden können. Der nebenstehende Screenshot zeigt einen typischen Eintrag in der DBLog von FHEM.&lt;br /&gt;
[[Datei:TypischerQuery.png |200px|thumb|right|Typischer Eintrag in der DBLog]]  &lt;br /&gt;
&lt;br /&gt;
Beim den VALUE Einträgen von FHEM muss man beachten, dass diese (da sie auch Text beinhalten können) nicht numerisch sind. Soll schon intern im SELECT eine Berechnung durchgeführt werden wie AVG oder MIN/MAX, dann muss man hier CONVERT(VALUE, DOUBLE) oder CONVERT(VALUE, INTEGER) verwenden. &lt;br /&gt;
&lt;br /&gt;
Ein Beispieleintrag sieht wie folgt aus&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
 SELECT&lt;br /&gt;
 UNIX_TIMESTAMP(TIMESTAMP) as time_sec,&lt;br /&gt;
 VALUE as value,  &amp;quot;Kurvenbezeichnung&amp;quot; as metric &lt;br /&gt;
 FROM history WHERE READING=&amp;quot;state&amp;quot;  AND DEVICE=&amp;quot;MyDummy&amp;quot; AND $__timeFilter( TIMESTAMP )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr numerische Werte in einer Grafik ausgeben wollen, müsst Ihr das Text-Feld VALUE mittels &#039;&#039;&#039;cast(VALUE as signed)&#039;&#039;&#039;  konvertieren&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
 SELECT&lt;br /&gt;
 UNIX_TIMESTAMP(TIMESTAMP) as time_sec,&lt;br /&gt;
 cast(VALUE as signed) as value,  &amp;quot;Kurvenbezeichnung&amp;quot; as metric &lt;br /&gt;
 FROM history WHERE READING=&amp;quot;state&amp;quot;  AND DEVICE=&amp;quot;MyDummy&amp;quot; AND $__timeFilter( TIMESTAMP )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Macros ===&lt;br /&gt;
Grafana bietet ein paar Macros die man in den MySQL Selects verwenden kann, um die zu ladenden Daten auf den angezeigten Zeitraum zu begrenzen.&lt;br /&gt;
* $__timeFilter(TIMESTAMP) liefert eine Überprüfung auf einen Zeitraum zurück, die man in der WHERE Bedingung verwenden kann (siehe obiges Beispiel)&lt;br /&gt;
* $__timeFrom() liefert den Startzeitpunkt des angezeigten Zeitraums als &amp;quot;YYYY-MM-DD HH:MM:SS&amp;quot; zurück.&lt;br /&gt;
* $__timeTo() liefert den Endzeitpunkt des angezeigten Zeitraums als &amp;quot;YYYY-MM-DD HH:MM:SS&amp;quot; zurück (so loggt auch DBLog in die Datenbank).&lt;br /&gt;
* $__unixEpochFrom() liefert den Startzeitpunkt des angezeigten Zeitraums als UNIX-Timestamp Format (Sekunden seit 01.01.1970) zurück.&lt;br /&gt;
* $__unixEpochTo liefert den Endzeitpunkt des angezeigten Zeitraums als UNIX-Timestamp Format (Sekunden seit 01.01.1970) zurück.&lt;br /&gt;
&lt;br /&gt;
=== Beispiele ===&lt;br /&gt;
Sehr viele Beispiele hat Thyraz in diesem {{Link2Forum|Topic=77724|LinkText=Foreneintrag}} bereitgestellt. Eine ausführliche Erläuterung zu einen Anzeige von Differenzwerten finden sich in diesem [https://forum.fhem.de/index.php/topic,77724.msg1023943.html#msg1023943 Foreneintrag].&lt;br /&gt;
&lt;br /&gt;
=== Einbindung in FHEM (und andere Seiten) ===&lt;br /&gt;
Die Grafiken können mit einem URL einfach in FHEM und andere Seiten eingebunden werden. Die entsprechende Adresse lautet dann&lt;br /&gt;
 http://&amp;lt;URL-Grafana-Server&amp;gt;:3000/render/dashboard/db/&amp;lt;Name-des-Dashboards&amp;gt;?orgId=2&amp;amp;from=now%2Fd&amp;amp;to=now&amp;amp;panelId=1&amp;amp;width=750&amp;amp;height=300&amp;amp;tz=UTC%2B02%3A00&lt;br /&gt;
Dabei ist der Teil der URL from=now%2Fd&amp;amp;to=now individuell veränderbar. Standardmäßig sind das fixe Zeitpunkte (wie im Beispiel mit 1507705926296). Mit &amp;quot;Now&amp;quot; etc. kann man das dynamisch gestalten und so einen alternativen, dynamischen Plot im FHEM darstellen:&lt;br /&gt;
* from=now%2Fd&amp;amp;to=now: Today so far&lt;br /&gt;
* from=now-30d&amp;amp;to=now: Die letzten 30 Tage&lt;br /&gt;
* from=now-395d&amp;amp;to=now-365d: Die letzten 30 Tage vor einem Jahr (Temperaturvergleich zum Vorjahr z.B.)&lt;br /&gt;
&lt;br /&gt;
Das entsprechende device, das in FHEMWEB die Grafik zur Verfügung stellt, ist dann weblink:&lt;br /&gt;
 defmod &amp;lt;device_name&amp;gt; weblink image &amp;lt;HTTP-Adresse&amp;gt;:3000/render/dashboard-solo/db/&amp;lt;Datenbankname&amp;gt;?orgId=2&amp;amp;from=now%2Fd&amp;amp;to=now&amp;amp;panelId=1&amp;amp;width=750&amp;amp;height=300&amp;amp;tz=UTC%2B02%3A00&lt;br /&gt;
&lt;br /&gt;
Entsprechende Attribute sind auch möglich:&lt;br /&gt;
 attr &amp;lt;device-name&amp;gt; htmlattr width=&amp;quot;750&amp;quot; height=&amp;quot;300&amp;quot; frameborder=&amp;quot;0&amp;quot; title=&amp;quot;Aktueller Verlauf&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei FTUI würde man das Image Widget verwenden. Will man die Grafiken mit iframe einbinden, so muss zuerst in Grafana eine Sicherheitseinstellung verändert werden, die eigentlich eine solche iframe-Einbindung verhindert. Dazu fügt man im Security-Abschnitt der grafana.ini folgende Zeile ein&lt;br /&gt;
 [security]&lt;br /&gt;
 allow_embedding = true&lt;br /&gt;
und startet danach den grafana-server neu.&lt;br /&gt;
&lt;br /&gt;
=== Speichern und Senden von Grafiken (z.B. mit Telegram) ===&lt;br /&gt;
Will man Grafiken von Grafana mit Telegram oder anderen Messenger-Programmen versenden, sind mehrere Schritte notwendig. Zuerst muss die Datei &amp;quot;gerendert&amp;quot; und lokal gespeichert werden, danach kann man sie versenden. Da das Rendern &#039;&#039;mehrere Sekunden&#039;&#039; dauern kann, sollte dieser Vorgang entweder nonblocking oder sogar außerhalb von FHEM erfolgen. &lt;br /&gt;
 &lt;br /&gt;
==== Erster Schritt: Rendern ====&lt;br /&gt;
Grafana verwendet eine Authentifizierungsmethode, die beim Rendern zu berücksichtigen ist. Tut man das nicht, so erhält man keine Grafik, sondern nur eine HTML-Datei die eben anzeigt, dass der Zugriff nicht authentifiziert erfolgte. Um sich zu authentifizieren, muss man einen neuen Nutzer anlegen und einen API-Key anfordern.&lt;br /&gt;
&lt;br /&gt;
[[Datei:GrafanaAPIKey.png|200px|thumb|right|Auswahl des API-Key im Grafana-Menü]]&lt;br /&gt;
Im Hauptmenü von Grafana wählt man links oben unter &amp;quot;admin&amp;quot; den Eintrag API-Key aus. Dort legt man einen neuen Benutzer an und notiert sich den Schlüssel (er wird nur einmal angezeigt). Dieser Schlüssel ist eine sehr lange Zeichenkette, beispielsweise &amp;quot;0NWcWRCVjZtSkd81NG1EOEprdVYxRUJtZWZeyJrIjoidUNycWRCVjZtSkd0NW81NGX0=&amp;quot;. Im Folgenden möge die Zeichenkette mit &amp;lt;Schluessel&amp;gt; bezeichnet werden.&lt;br /&gt;
&lt;br /&gt;
Mit dieser Authentifizierungsschlüssel kann man nun auf Grafana zugreifen. Beispielsweise möchte man ein dashboard, das mehrere Temperaturen enthält, rendern. Dazu benötigt man nun die Zugriffsadresse dieses Dashboards. Man klickt auf die Überschrift des Boards und wählt &amp;quot;Share&amp;quot; aus. Es erscheint ein Share Panel, so wie im Screenshot angezeigt.&lt;br /&gt;
[[Datei:GrafanaSharePanel.png|200px|thumb|right|Grafana Share Panel]] &lt;br /&gt;
Unten im Panel ist ein Link mit den Worten &amp;quot;Direct link rendered image&amp;quot; zu sehen. Diesen Link notiert man. Im folgenden möge der Link mit &amp;lt;Link&amp;gt; bezeichnet werden.&lt;br /&gt;
&lt;br /&gt;
Auf der Shell-Ebene würde nun der folgende Befehl das Dashboard rendern und speichern&lt;br /&gt;
 curl -H &amp;quot;Authorization: Bearer &amp;lt;Schluessel&amp;gt;&amp;quot; &amp;quot;&amp;lt;Link&amp;gt;&amp;quot;  &amp;lt;Dateiname&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da in der neuen Grafana-Version das Rendern &#039;&#039;auf einem Raspberry Pi&#039;&#039; nicht ohne Weiteres unterstützt wird, kann es sein, dass die oben genannten Versuche fehlschlagen. Hier bietet sich eine andere Lösung an, die zwar nicht so elegant wie die obige ist, aber dafür funktioniert: Man installiert Firefox auf dem Raspberry und lässt ihn &amp;quot;headless&amp;quot; einen Screenshot erstellen. Dieses kann man dann weiterverarbeiten. Diese Lösung hat den Nachteil, dass dann nur die Auflösung des Raspberry erreicht wird. Dazu sind folgende Schritte noztwendig. Zuerst Firefox installieren&lt;br /&gt;
  sudo apt install firefox-esr&lt;br /&gt;
danach ein neues Profil in Firefox erstellen (sonst stürzt Firefox ab), das ist sehr umständlich: Auf Hilfe gehen, dann steht dort irgendwo &amp;quot;install new profile&amp;quot; und dieses Profil beispielsweise headless_profil nennen und zuletzt kann dann endlich mit einem Terminal-Befehl ein Screenshot erstellt werden&lt;br /&gt;
 /pfad/zu/firefox -P headless_profile -headless --screenshot &amp;lt;hier die www-Adresse der Webseite angeben&amp;gt;&lt;br /&gt;
Mehr dazu auf [https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode dieser Webseite]&lt;br /&gt;
&lt;br /&gt;
==== Zweiter Schritt: Senden mit Telegram ====&lt;br /&gt;
Im zweiten Schritt soll nun die Datei gesendet werden. Dazu kann man etwa den [[TelegramBot|Telegram-Bot]] verwenden. Der Sendebefehl lautet&lt;br /&gt;
 set &amp;lt;TelegramBotDevice-Name&amp;gt; sendImage &amp;lt;Dateiname&amp;gt;&lt;br /&gt;
Dabei ist der Dateiname des Bild (png-Format) anzugeben.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=34159</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=34159"/>
		<updated>2020-11-01T20:23:27Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Passworte */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore 10 Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Python3]]&lt;br /&gt;
&amp;lt;!-- |ModOwner=  --&amp;gt;&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Bild:Plenticore FHEM 1.png|mini|900px|rechts|Die Diagramme im Überblick]]&lt;br /&gt;
[[Bild:Plenticore FHEM 2.png|mini|900px|rechts|Geräte Überblick mit manueller Schaltmöglichkeit]]&lt;br /&gt;
[[Bild:Plenticore FHEM 3.png|mini|900px|rechts|Steuerungsgeräte für die Schaltlogik]]&lt;br /&gt;
[[Bild:Plenticore FHEM 4.png|mini|900px|rechts|ReadingsGroup für die schnelle Parametereinstellung]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus]] [https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/ Hersteller Link] ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen Energietechnik ==&lt;br /&gt;
&lt;br /&gt;
Der Wechselrichter, der Speicher und der KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
== Geräte-Registrierung ==&lt;br /&gt;
&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
&lt;br /&gt;
== Hersteller Dokumentation ==&lt;br /&gt;
&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2018/06/15/11/40/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2018/04/12/08/26/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2018/04/12/08/26/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2019/03/12/07/13/kostal_update_plenticore_piko_iq_011504581.swu/ Plenticore Plus - Software Update UI: 01.15.04581 FW: 01.43]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2018/08/30/08/53/ba_kostal_interface_modbus-tcp_sunspec.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2019/03/06/13/17/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2019/03/06/13/17/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/06/09/11/49/kostal_update_ksem_1_2_1.zip/ KSEM - Software Update - 1.2.1]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2019/05/09/13/57/ba_kostal_interface_ksem---201911.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
== Einbindung in das Netzwerk ==&lt;br /&gt;
&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen FHEM Umfeld ==&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte müssen mit TCP/IP erreichbar sein ===&lt;br /&gt;
&lt;br /&gt;
=== Alle Module sollten auf einem aktuellen Stand sein ===&lt;br /&gt;
&lt;br /&gt;
=== Python ===&lt;br /&gt;
&lt;br /&gt;
==== Ein Python 3 sollte vorhanden sein ====&lt;br /&gt;
Wenn man die erweiterten Funktionalitäten, wie Statistiken, Speicher auslesen und später auch das Setzen von Werten im Plenticore, verwenden möchte.&lt;br /&gt;
&lt;br /&gt;
==== Es müssen folgende Python Module vorhanden sein ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
python3-pip&lt;br /&gt;
&lt;br /&gt;
pip3 install pycryptodome&lt;br /&gt;
pip3 install -U fhem&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Eine LogDB/LogDBRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird. ===&lt;br /&gt;
&lt;br /&gt;
=== Verwendete Module ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Modbus&lt;br /&gt;
- HTTPMOD&lt;br /&gt;
- expandJSON&lt;br /&gt;
- DbLog&lt;br /&gt;
- DbRep&lt;br /&gt;
- dummy&lt;br /&gt;
- Shelly&lt;br /&gt;
- HourCounter&lt;br /&gt;
- readingsGroup&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Einbindung in FHEM: Überblick ==&lt;br /&gt;
&lt;br /&gt;
=== Hardware Anbindung (alles über LAN) ===&lt;br /&gt;
&lt;br /&gt;
==== Kostal Plenticore Plus ====&lt;br /&gt;
===== Kostal Plenticore Plus die Basis information (Modbus/TCP) =====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
====== Plenticore Modbus Definition ======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Modbus Timing ======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
====== RAW Definition PV_Anlage_1_config ======&lt;br /&gt;
Diese Dummy soll alle Konfigurationsparameter halten, auf die dann die anderen Geräte Definitionen zentral zugreifen. Hier können auch default Namen und Vorschläge für Werte in Form von Slidern und Auswahllisten hinterlegt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Anlage_1_config dummy&lt;br /&gt;
attr PV_Anlage_1_config DbLogExclude .*&lt;br /&gt;
attr PV_Anlage_1_config alias PV_Anlage_1_config&lt;br /&gt;
attr PV_Anlage_1_config comment Steht das reading module_*_count auf 0 wird diese Ausrichtung nicht berücksichtigt\&lt;br /&gt;
Passworte zu dieser Konfiguration liegen im Dateiverzeichnis ~./python/pwd_*.json\&lt;br /&gt;
\&lt;br /&gt;
Korrekturkurven:\&lt;br /&gt;
         Steilheit  Parallel\&lt;br /&gt;
                    verschiebung\&lt;br /&gt;
tempk      -0.39      25\&lt;br /&gt;
cloudk     -0.65       0\&lt;br /&gt;
raink      -0.30       0\&lt;br /&gt;
Der Slider für die Steilheit wird mit - k/100 umgerechnet. 39 ==&amp;gt; -0.39&lt;br /&gt;
attr PV_Anlage_1_config event-on-change-reading .*&lt;br /&gt;
attr PV_Anlage_1_config group PV Eigenverbrauch&lt;br /&gt;
attr PV_Anlage_1_config icon solar_icon&lt;br /&gt;
attr PV_Anlage_1_config readingList IP-Address_Plenticore IP-Address_BYD IP-Address_KSEM IP-Address_FHEM module_1_active module_2_active module_3_active module_1_name module_2_name module_3_name module_1_direction module_2_direction module_3_direction module_1_count module_2_count module_3_count module_1_power module_2_power module_3_power module_1_plain module_2_plain module_3_plain forecast_cloudk forecast_cloudk_base forecast_raink forecast_raink_base forecast_tempk forecast_tempk_base forecast_factor Forecast_Station Battery_Total_Power&lt;br /&gt;
attr PV_Anlage_1_config room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Anlage_1_config setList IP-Address_Plenticore IP-Address_BYD IP-Address_KSEM IP-Address_FHEM module_1_name:East,SouthEast,South,SouthWest,West,Garage,CarPort module_2_name:East,SouthEast,South,SouthWest,West module_3_name:East,SouthEast,South,SouthWest,West module_1_direction:slider,-90,5,+90 module_2_direction:slider,-90,5,90 module_3_direction:slider,-90,5,90 module_1_count:slider,0,1,40 module_2_count:slider,0,1,40 module_3_count:slider,0,1,40 module_1_power:slider,250,10,400 module_2_power:slider,250,10,400 module_3_power:slider,250,10,400 module_1_plain:slider,15,1,45 module_2_plain:slider,15,1,45 module_3_plain:slider,15,1,45 forecast_cloudk:slider,0,1,100 forecast_cloudk_base:slider,0,1,10 forecast_raink:slider,0,1,100 forecast_raink_base:slider,0,1,10 forecast_tempk:slider,0,1,100 forecast_tempk_base:slider,10,1,30 forecast_factor:1,1.5,2,2.5,3,3.5,4,4.5,5 Forecast_Station Battery_Total_Power&lt;br /&gt;
attr PV_Anlage_1_config sortby 04&lt;br /&gt;
attr PV_Anlage_1_config verbose 0&lt;br /&gt;
&lt;br /&gt;
setstate PV_Anlage_1_config state&lt;br /&gt;
setstate PV_Anlage_1_config 2020-09-11 07:12:49 Battery_Total_Power 8960&lt;br /&gt;
setstate PV_Anlage_1_config 2020-09-11 07:36:39 Forecast_Station &amp;lt;Station&amp;gt;&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:44:46 IP-Address_BYD 192.168.178.10&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:39:26 IP-Address_FHEM 192.168.178.11&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:43:27 IP-Address_KSEM 192.168.178.12&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:39:44 IP-Address_Plenticore 192.168.178.13&lt;br /&gt;
setstate PV_Anlage_1_config 2020-09-02 18:39:15 forecast_cloudk 20&lt;br /&gt;
setstate PV_Anlage_1_config 2020-09-03 11:43:57 forecast_cloudk_base 0&lt;br /&gt;
setstate PV_Anlage_1_config 2020-09-02 18:40:29 forecast_raink 20&lt;br /&gt;
setstate PV_Anlage_1_config 2020-09-01 12:52:40 forecast_raink_base 0&lt;br /&gt;
setstate PV_Anlage_1_config 2020-09-01 12:46:57 forecast_tempk 39&lt;br /&gt;
setstate PV_Anlage_1_config 2020-09-01 12:50:06 forecast_tempk_base 25&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:27:30 module_1_count 0&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:27:38 module_1_direction -90&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:27:48 module_1_name East&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:29:42 module_1_plain 40&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:31:09 module_1_power 300&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:31:21 module_2_count 0&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:33:55 module_2_direction 0&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:34:03 module_2_name South&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:34:14 module_2_plain 40&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:34:25 module_2_power 300&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:34:42 module_3_count 0&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:34:50 module_3_direction 90&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:35:00 module_3_name West&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:35:08 module_3_plain 40&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:35:16 module_3_power 300&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== RAW Definition PV_Anlage_1 ======&lt;br /&gt;
Für den Zugriff auf die Plenticore ModBus/TCP Daten wird dieses Device verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Anlage_1 ModbusAttr 71 60 &amp;lt;IP-Address_Plenticore&amp;gt;:1502 TCP&lt;br /&gt;
attr PV_Anlage_1 DbLogExclude .*&lt;br /&gt;
attr PV_Anlage_1 DbLogInclude Act_state_of_charge,Actual_battery_charge_-minus_or_discharge_-plus_Power,Actual_battery_charge_usable_Power,Battery_temperature,Home_own_consumption_from_PV,Home_own_consumption_from_battery,Home_own_consumption_from_grid,Inverter_state,Power_DC1,Power_DC2,Power_DC_Sum,Total_DC_Power,Total_DC_Power_Max,Total_PV_Power_reserve,Voltage_DC1,Voltage_DC2&lt;br /&gt;
attr PV_Anlage_1 alias PV_Einspeisung&lt;br /&gt;
attr PV_Anlage_1 comment Kostal Plenticore 10 Plus mit BYD Speicher&lt;br /&gt;
attr PV_Anlage_1 dev-h-defFormat %.2f&lt;br /&gt;
attr PV_Anlage_1 dev-h-defLen 2&lt;br /&gt;
attr PV_Anlage_1 dev-h-defPoll 1&lt;br /&gt;
attr PV_Anlage_1 dev-h-defRevRegs 1&lt;br /&gt;
attr PV_Anlage_1 dev-h-defUnpack f&amp;gt;&lt;br /&gt;
attr PV_Anlage_1 dev-type-STR-format %s&lt;br /&gt;
attr PV_Anlage_1 dev-type-STR-len 8&lt;br /&gt;
attr PV_Anlage_1 dev-type-STR-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 dev-type-STR-unpack a*&lt;br /&gt;
attr PV_Anlage_1 event-on-change-reading Act_state_of_charge,Actual_battery_charge_.*,Battery_temperature,Home_own_consumption_from_.*,Inverter_state,Power_DC1,Power_DC2,Power_DC_Sum,Total_DC_Power,Total_DC_Power_Max,Total_PV_Power_reserve,Voltage_DC1,Voltage_DC2,.*_yield,Solar_.*&lt;br /&gt;
attr PV_Anlage_1 group PV Eigenverbrauch&lt;br /&gt;
attr PV_Anlage_1 icon sani_solar&lt;br /&gt;
attr PV_Anlage_1 obj-h100-reading Total_DC_Power&lt;br /&gt;
attr PV_Anlage_1 obj-h104-format %s&lt;br /&gt;
attr PV_Anlage_1 obj-h104-reading State_of_energy_manager&lt;br /&gt;
attr PV_Anlage_1 obj-h104-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 obj-h104-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h106-reading Home_own_consumption_from_battery&lt;br /&gt;
attr PV_Anlage_1 obj-h108-reading Home_own_consumption_from_grid&lt;br /&gt;
attr PV_Anlage_1 obj-h110-reading Total_home_consumption_Battery&lt;br /&gt;
attr PV_Anlage_1 obj-h112-reading Total_home_consumption_Grid&lt;br /&gt;
attr PV_Anlage_1 obj-h114-reading Total_home_consumption_PV&lt;br /&gt;
attr PV_Anlage_1 obj-h116-reading Home_own_consumption_from_PV&lt;br /&gt;
attr PV_Anlage_1 obj-h118-reading Total_home_consumption&lt;br /&gt;
attr PV_Anlage_1 obj-h120-reading Isolation_resistance&lt;br /&gt;
attr PV_Anlage_1 obj-h122-reading Power_limit_from_EVU&lt;br /&gt;
attr PV_Anlage_1 obj-h124-reading Total_home_consumption_rate&lt;br /&gt;
attr PV_Anlage_1 obj-h14-reading Inverter_serial_number&lt;br /&gt;
attr PV_Anlage_1 obj-h14-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h144-reading Worktime&lt;br /&gt;
attr PV_Anlage_1 obj-h150-reading Actual_cos_phi&lt;br /&gt;
attr PV_Anlage_1 obj-h152-reading Grid_frequency&lt;br /&gt;
attr PV_Anlage_1 obj-h154-reading Current_Phase_1&lt;br /&gt;
attr PV_Anlage_1 obj-h156-reading Active_power_Phase_1&lt;br /&gt;
attr PV_Anlage_1 obj-h158-reading Voltage_Phase_1&lt;br /&gt;
attr PV_Anlage_1 obj-h160-reading Current_Phase_2&lt;br /&gt;
attr PV_Anlage_1 obj-h162-reading Active_power_Phase_2&lt;br /&gt;
attr PV_Anlage_1 obj-h164-reading Voltage_Phase_2&lt;br /&gt;
attr PV_Anlage_1 obj-h166-reading Current_Phase_3&lt;br /&gt;
attr PV_Anlage_1 obj-h168-reading Active_power_Phase_3&lt;br /&gt;
attr PV_Anlage_1 obj-h170-reading Voltage_Phase_3&lt;br /&gt;
attr PV_Anlage_1 obj-h172-reading Total_AC_active_power&lt;br /&gt;
attr PV_Anlage_1 obj-h174-reading Total_AC_reactive_power&lt;br /&gt;
attr PV_Anlage_1 obj-h178-reading Total_AC_apparent_power&lt;br /&gt;
attr PV_Anlage_1 obj-h190-reading Battery_charge_current&lt;br /&gt;
attr PV_Anlage_1 obj-h194-format %.0f&lt;br /&gt;
attr PV_Anlage_1 obj-h194-reading Number_of_battery_cycles&lt;br /&gt;
attr PV_Anlage_1 obj-h200-reading Actual_battery_charge_-minus_or_discharge_-plus_current&lt;br /&gt;
attr PV_Anlage_1 obj-h202-reading PSSB_fuse_state&lt;br /&gt;
attr PV_Anlage_1 obj-h208-format %.0f&lt;br /&gt;
attr PV_Anlage_1 obj-h208-reading Battery_ready_flag&lt;br /&gt;
attr PV_Anlage_1 obj-h210-reading Act_state_of_charge&lt;br /&gt;
attr PV_Anlage_1 obj-h212-reading Battery_state&lt;br /&gt;
attr PV_Anlage_1 obj-h214-reading Battery_temperature&lt;br /&gt;
attr PV_Anlage_1 obj-h216-reading Battery_voltage&lt;br /&gt;
attr PV_Anlage_1 obj-h218-reading Cos_phi_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h220-reading Frequency_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h222-reading Current_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h224-reading Active_power_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h226-reading Reactive_power_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h228-reading Apparent_power_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h230-reading Voltage_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h232-reading Current_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h234-reading Active_power_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h236-reading Reactive_power_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h238-reading Apparent_power_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h240-reading Voltage_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h242-reading Current_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h244-reading Active_power_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h246-reading Reactive_power_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h248-reading Apparent_power_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h250-reading Voltage_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h252-reading Total_active_power_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h254-reading Total_reactive_power_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h256-reading Total_apparent_power_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h258-reading Current_DC1&lt;br /&gt;
attr PV_Anlage_1 obj-h260-reading Power_DC1&lt;br /&gt;
attr PV_Anlage_1 obj-h266-reading Voltage_DC1&lt;br /&gt;
attr PV_Anlage_1 obj-h268-reading Current_DC2&lt;br /&gt;
attr PV_Anlage_1 obj-h270-reading Power_DC2&lt;br /&gt;
attr PV_Anlage_1 obj-h276-reading Voltage_DC2&lt;br /&gt;
attr PV_Anlage_1 obj-h278-reading Current_DC3&lt;br /&gt;
attr PV_Anlage_1 obj-h280-reading Power_DC3&lt;br /&gt;
attr PV_Anlage_1 obj-h286-reading Voltage_DC3&lt;br /&gt;
attr PV_Anlage_1 obj-h320-reading Total_yield&lt;br /&gt;
attr PV_Anlage_1 obj-h322-reading Daily_yield&lt;br /&gt;
attr PV_Anlage_1 obj-h324-reading Yearly_yield&lt;br /&gt;
attr PV_Anlage_1 obj-h326-reading Monthly_yield&lt;br /&gt;
attr PV_Anlage_1 obj-h38-reading Software-Version_Maincontroller_(MC)&lt;br /&gt;
attr PV_Anlage_1 obj-h38-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h384-len 16&lt;br /&gt;
attr PV_Anlage_1 obj-h384-reading Inverter_network_name&lt;br /&gt;
attr PV_Anlage_1 obj-h384-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h420-reading IP-address&lt;br /&gt;
attr PV_Anlage_1 obj-h420-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h428-reading IP-subnetmask&lt;br /&gt;
attr PV_Anlage_1 obj-h428-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h436-reading IP-gateway&lt;br /&gt;
attr PV_Anlage_1 obj-h436-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h446-reading IP-DNS1&lt;br /&gt;
attr PV_Anlage_1 obj-h446-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h454-reading IP-DNS2&lt;br /&gt;
attr PV_Anlage_1 obj-h454-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h46-reading Software-Version_IO-Controller_(IOC)&lt;br /&gt;
attr PV_Anlage_1 obj-h46-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h514-len 1&lt;br /&gt;
attr PV_Anlage_1 obj-h514-reading Battery_actual_SOC&lt;br /&gt;
attr PV_Anlage_1 obj-h517-reading Battery_Manufacturer&lt;br /&gt;
attr PV_Anlage_1 obj-h517-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h525-format %c&lt;br /&gt;
attr PV_Anlage_1 obj-h525-reading Battery_Model_ID&lt;br /&gt;
attr PV_Anlage_1 obj-h525-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h527-format %c&lt;br /&gt;
attr PV_Anlage_1 obj-h527-reading Battery_Serial_Number&lt;br /&gt;
attr PV_Anlage_1 obj-h529-len 4&lt;br /&gt;
attr PV_Anlage_1 obj-h529-reading Work_Capacity&lt;br /&gt;
attr PV_Anlage_1 obj-h529-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h531-format %.0f&lt;br /&gt;
attr PV_Anlage_1 obj-h531-reading Inverter_Max_Power&lt;br /&gt;
attr PV_Anlage_1 obj-h531-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h535-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 obj-h535-unpack n&lt;br /&gt;
attr PV_Anlage_1 obj-h551-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 obj-h559-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 obj-h56-format %.0f&lt;br /&gt;
attr PV_Anlage_1 obj-h56-reading Inverter_state&lt;br /&gt;
attr PV_Anlage_1 obj-h56-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h575-len 1&lt;br /&gt;
attr PV_Anlage_1 obj-h575-reading Inverter_Generation_Power_(actual)&lt;br /&gt;
attr PV_Anlage_1 obj-h577-len 2&lt;br /&gt;
attr PV_Anlage_1 obj-h577-reading Generation_Energy&lt;br /&gt;
attr PV_Anlage_1 obj-h577-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h578-reading Total_energy&lt;br /&gt;
attr PV_Anlage_1 obj-h582-reading Actual_battery_charge-discharge_power&lt;br /&gt;
attr PV_Anlage_1 obj-h586-format %s&lt;br /&gt;
attr PV_Anlage_1 obj-h586-reading Battery_Firmware&lt;br /&gt;
attr PV_Anlage_1 obj-h586-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h588-format %s&lt;br /&gt;
attr PV_Anlage_1 obj-h588-len 1&lt;br /&gt;
attr PV_Anlage_1 obj-h588-reading Battery_Type&lt;br /&gt;
attr PV_Anlage_1 obj-h588-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h6-reading Inverter_article_number&lt;br /&gt;
attr PV_Anlage_1 obj-h6-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h768-len 32&lt;br /&gt;
attr PV_Anlage_1 obj-h768-reading Productname&lt;br /&gt;
attr PV_Anlage_1 obj-h768-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h800-len 32&lt;br /&gt;
attr PV_Anlage_1 obj-h800-reading Power_class&lt;br /&gt;
attr PV_Anlage_1 obj-h800-type STR&lt;br /&gt;
attr PV_Anlage_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Anlage_1 sortby 01&lt;br /&gt;
attr PV_Anlage_1 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TH ALIGN=\&amp;quot;MIDDLE\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;Batterie %s&amp;lt;/TH&amp;gt;\&lt;br /&gt;
  &amp;lt;TH ALIGN=\&amp;quot;MIDDLE\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;aktuell&amp;lt;/TH&amp;gt;\&lt;br /&gt;
  &amp;lt;TH ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;Hausverbrauch&amp;lt;/TH&amp;gt;\&lt;br /&gt;
  &amp;lt;TH ALIGN=\&amp;quot;MIDDLE\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;Erträge&amp;lt;/TH&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD ALIGN=\&amp;quot;MIDDLE\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;\&lt;br /&gt;
    Leistung:  %04d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    Temp.: %02.1f °C&amp;lt;br&amp;gt;\&lt;br /&gt;
    Ladung total: %2d %%&amp;lt;br&amp;gt;\&lt;br /&gt;
    Ladung Res.: %04d Wh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;\&lt;br /&gt;
    DC total: %05d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    &amp;lt;br&amp;gt;\&lt;br /&gt;
    &amp;lt;br&amp;gt;\&lt;br /&gt;
    PV reserve: %05d W\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;\&lt;br /&gt;
    von PV: %05d W &amp;lt;br&amp;gt;\&lt;br /&gt;
    von Batterie: %05d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    vom Netz: %05d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    ins Haus: %05d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    Netz: %05d W\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;\&lt;br /&gt;
    Tag: %05d KWh &amp;lt;br&amp;gt;\&lt;br /&gt;
    Monat: %05d KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Jahr: %05d KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Total: %05d KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; , \&lt;br /&gt;
(ReadingsVal($name,&amp;quot;Actual_battery_charge_-minus_or_discharge_-plus_Power&amp;quot;,0) lt 0) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;Laden&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Entladen&amp;lt;/span&amp;gt;&amp;quot; ,\&lt;br /&gt;
\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Actual_battery_charge_-minus_or_discharge_-plus_Power&amp;quot;,0),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Battery_temperature&amp;quot;,0) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Act_state_of_charge&amp;quot;,0) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Actual_battery_charge_usable_Power&amp;quot;,0) ,\&lt;br /&gt;
\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Power_DC_Sum&amp;quot;,&amp;quot;0&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Total_PV_Power_reserve&amp;quot;,&amp;quot;0&amp;quot;),\&lt;br /&gt;
\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Home_own_consumption_from_PV&amp;quot;,0) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Home_own_consumption_from_battery&amp;quot;,0) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Home_own_consumption_from_grid&amp;quot;,0),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Home_own_consumption_from_PV&amp;quot;,0) +ReadingsVal($name,&amp;quot;Home_own_consumption_from_battery&amp;quot;,0)+ReadingsVal($name,&amp;quot;Home_own_consumption_from_grid&amp;quot;,0),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0),\&lt;br /&gt;
\&lt;br /&gt;
round(ReadingsVal($name,&amp;quot;Daily_yield&amp;quot;,0)/1000 ,0),\&lt;br /&gt;
round(ReadingsVal($name,&amp;quot;Monthly_yield&amp;quot;,0)/1000 ,0) ,\&lt;br /&gt;
round(ReadingsVal($name,&amp;quot;Yearly_yield&amp;quot;,0)/1000 ,0) ,\&lt;br /&gt;
round(ReadingsVal($name,&amp;quot;Total_yield&amp;quot;,0)/1000 ,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr PV_Anlage_1 userReadings Power_DC_Sum:Total_DC_Power.* { ReadingsVal($NAME,&amp;quot;Power_DC1&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal($NAME,&amp;quot;Power_DC2&amp;quot;,&amp;quot;0&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
Total_PV_Power_reserve:Total_DC_Power.* {my $reserve = ReadingsVal($NAME,&amp;quot;Power_DC_Sum&amp;quot;,&amp;quot;0&amp;quot;) * 0.90 - ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_PV&amp;quot;,&amp;quot;0&amp;quot;);;;; ($reserve lt 0)?0:round($reserve,3)  },\&lt;br /&gt;
\&lt;br /&gt;
Total_DC_Power_Max:Total_DC_Power.* { my $Bat_out = (ReadingsVal($NAME,&amp;quot;Actual_battery_charge_-minus_or_discharge_-plus_current&amp;quot;,&amp;quot;0&amp;quot;)*ReadingsVal($NAME,&amp;quot;Battery_voltage&amp;quot;,&amp;quot;0&amp;quot;));;;; ($Bat_out gt 0)?ReadingsVal($NAME,&amp;quot;Power_DC_Sum&amp;quot;,&amp;quot;0&amp;quot;) + $Bat_out :ReadingsVal($NAME,&amp;quot;Power_DC_Sum&amp;quot;,&amp;quot;0&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
Actual_battery_charge_-minus_or_discharge_-plus_Power:Actual_battery_charge_-minus_or_discharge_-plus_current.* {round((ReadingsVal($NAME,&amp;quot;Actual_battery_charge_-minus_or_discharge_-plus_current&amp;quot;,&amp;quot;0&amp;quot;)*ReadingsVal($NAME,&amp;quot;Battery_voltage&amp;quot;,&amp;quot;0&amp;quot;)),0)},\&lt;br /&gt;
\&lt;br /&gt;
Actual_battery_charge_usable_Power:Act_state_of_charge.* {my $x = (ReadingsVal($NAME.&amp;quot;_config&amp;quot;,&amp;quot;Battery_Total_Power&amp;quot;,&amp;quot;0&amp;quot;)*(ReadingsVal($NAME,&amp;quot;Act_state_of_charge&amp;quot;,&amp;quot;0&amp;quot;)-10)/100);; ($x lt 0)?0:round($x,0) }&lt;br /&gt;
attr PV_Anlage_1 verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Userreadings ======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userreadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind. Dies betrifft insbesondere die Statistics_* readings, die durch ein Python Skript später erzeugt werden.&lt;br /&gt;
&lt;br /&gt;
Power_DC_Sum&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Dies berechnet direkt die Summe der DC-Leistung. Wenn der Plenticore einen Speicher hat, wird dieser am String 3 angeschlossen,&lt;br /&gt;
   sollte also kein Speicher vorhanden sein muss man hier den dritten String auch noch addieren.&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_Anlage_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
&lt;br /&gt;
===== Kostal Plenticore Plus die API (über HTTPMOD mit Python Skript Authentifizierung) =====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Für diesen API Zugang über HTTP steht nun ein neues Gerät zur Verfügung, dass mit HTTPMOD und Python Authentifizierungsskripten die mehrstufige Anmeldung durchführt. Das ganze soll in Zukunft den starren Zugriff auf die Statistiken ablösen und eine Erweiterung zum setzen von Parametern im Plenticore bieten.&lt;br /&gt;
&lt;br /&gt;
====== Umstellungsaufwand, falls jemand früher eingestiegen ist. ======&lt;br /&gt;
Die erste Folge für den Umstieg ist, dass die Statistiken nicht mehr im PV_Anlage_1 Gerät abgelegt werden, da diese ja teil der API Abfrage sind. Das muss dann in der Bilanz berücksichtigt werden, da die Einträge dann unter dem neuen PV_Anlage_1_API Gerät abgelegt werden.&lt;br /&gt;
&lt;br /&gt;
2020.09.06 Die Umstellung auf das Plenticore API Gerät hat begonnen&lt;br /&gt;
&lt;br /&gt;
- Die Bilanz RAW Definition wurde aktualisiert&lt;br /&gt;
&lt;br /&gt;
- In der PV_Schedule Definition wurde das Kommando für die Aktualisierung der Statistik auf PV_Anlage_1_API umgestellt&lt;br /&gt;
&lt;br /&gt;
- Das Logging von Dum.Energy läuft wie gehabt weiter&lt;br /&gt;
&lt;br /&gt;
- Die Statistic_* readings aus dem PV_Anlage_1 Gerät können in der SQL Datenbank zum neuen PV_Anlage_1_API Gerät verschoben werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Bitte zuerst den Zeitraum, in dem die Statistikeinträge in die Datenbank geschrieben wurden feststellen.&lt;br /&gt;
MySQL [fhem]&amp;gt; SELECT TIMESTAMP,DEVICE,READING,VALUE FROM history WHERE DEVICE=&#039;PV_Anlage_1_API&#039; AND READING LIKE &#039;Statistic_%&#039; AND TIMESTAMP &amp;gt; &#039;2020-07-01 00:00:00&#039; ORDER BY TIMESTAMP LIMIT 500;&lt;br /&gt;
## Für den Update dann din Zeitraum so weit es geht einschränken, damit die Laufzeit in der Datenbank nicht so hoch wird.&lt;br /&gt;
MySQL [fhem]&amp;gt; UPDATE history SET TIMESTAMP=TIMESTAMP, DEVICE=&#039;PV_Anlage_1_API&#039; WHERE DEVICE=&#039;PV_Anlage_1&#039; AND READING LIKE &#039;Statistic_%&#039; AND TIMESTAMP &amp;gt; &#039;2020-07-01 00:00:00&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- Die alten Statistic_* readings können nun aus dem PV_Anlage_1 Gerät entfernt werden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
deletereading PV_Anlage_1 Statistic_.*&lt;br /&gt;
deletereading PV_Anlage_1 statistics_.*&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- Für das Logging kann nun im Attribut &amp;quot;DbLogInclude&amp;quot; ebenfalls &amp;quot;Statistic_.*&amp;quot; entfernt werden&lt;br /&gt;
&lt;br /&gt;
- Beim Attribut &amp;quot;event-on-change-reading&amp;quot; sind auch &amp;quot;statistics_.*,Statistic_.*&amp;quot; zu entfernen&lt;br /&gt;
&lt;br /&gt;
- Das userreading im PV_Anlage_1 kann ebenfalls geändert werden und um diese Zeile verkürzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
statistics_clean:statistics_output.* { my $x =  ReadingsVal($NAME,&amp;quot;statistics_output&amp;quot;,0);; $x =~ s/&amp;quot;moduleid&amp;quot;: &amp;quot;scb:statistic:EnergyFlow&amp;quot;, |, &amp;quot;moduleid&amp;quot;: &amp;quot;scb:statistic:EnergyFlow&amp;quot;|&amp;quot;processdata&amp;quot;: \[//g;; $x =~ s/id&amp;quot;: &amp;quot;|, &amp;quot;unit&amp;quot;: &amp;quot;&amp;quot;, &amp;quot;value&amp;quot;|^\[|\]\}\]$//g;; $x =~ s/moduleid/statistics_00_moduleid/g;; $x =~ s/processdata/statistics/g;; $x =~ s/\}\, \{/\, /g;; $x =~ s/\{\{/\{/g;; return $x }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- Nun noch das Gerät Plenticore_Statistics für das expandJSON löschen&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
delete Plenticore_Statistics&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Das sollten nun alle erforderlichen Bereinigungen für den Wechsel auf das PV_Anlage_1_API Gerät sein.&lt;br /&gt;
&lt;br /&gt;
====== Plenticore API ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Dateiverzeichnis ======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/fhem&lt;br /&gt;
/opt/fhem/python/pwd_fhem.json&lt;br /&gt;
/opt/fhem/python/pwd_plenticore.json&lt;br /&gt;
/opt/fhem/python/bin&lt;br /&gt;
/opt/fhem/python/bin/plenticore_auth_finish.py&lt;br /&gt;
/opt/fhem/python/bin/plenticore_auth_session.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Python 3 ======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ which python3&lt;br /&gt;
/usr/bin/python3&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ python3 --version&lt;br /&gt;
Python 3.7.3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Passworte ======&lt;br /&gt;
Die Passworte für den Plenticore und den FHEM Zugang liegen in einzelnen JSON Dateien.&lt;br /&gt;
Für den Plenticore wird das Passwort für den Benutzer &amp;quot;Anlagenbetreiber&amp;quot; verwendet, der bei der API als Benutzer &amp;quot;user&amp;quot; bezeichnet wird.&lt;br /&gt;
Im einfachsten Fall steht das Passwort auf dem Gehäuse, sofern es der Installateur nicht neu gesetzt hat. Testet es einfach mit einem Login im Web Interface des Plenticore.&lt;br /&gt;
&lt;br /&gt;
Für die Verbindung zum Fhem wird ein Python Modul verwendet, das einen Login mit http auf den Fhem Web Zugang macht.&lt;br /&gt;
Für eine passwortlose Verbindung werden username und password mit &amp;quot;&amp;quot; angegeben.&lt;br /&gt;
&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_plenticore.json&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;,&lt;br /&gt;
    &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Steht auf dem Gehäuse&amp;gt;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_fhem.json&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;username&amp;quot;: &amp;quot;&amp;lt;Ein Fhem Web User&amp;gt;&amp;quot;,&lt;br /&gt;
    &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Das Passwort des Users&amp;gt;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== plenticore_auth_* Erläuterung ======&lt;br /&gt;
Die folgenden beiden Skripte sind ein Extrakt aus den bisherigen Skripten, ohne die HTTP Aufrufe. Sie dienen nur noch der Generierung von Authentifizierungsschlüsseln. Optimaler Weise müssten sie auch noch nach Perl konvertiert werden, was für später geplant ist.&lt;br /&gt;
Als Übergabeparameter werden aus dem PV_Anlage_1_API Gerät Rückgabewerte der HTTP Aufrufe verwendet.&lt;br /&gt;
&lt;br /&gt;
====== plenticore_auth_finish ======&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ cat plenticore_auth_finish.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import string&lt;br /&gt;
import base64&lt;br /&gt;
import hashlib&lt;br /&gt;
import hmac&lt;br /&gt;
from Crypto.Cipher import AES&lt;br /&gt;
import binascii&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
import json&lt;br /&gt;
import fhem&lt;br /&gt;
&lt;br /&gt;
web          = sys.argv[1]&lt;br /&gt;
randomString = sys.argv[2]&lt;br /&gt;
nonce        = sys.argv[3]&lt;br /&gt;
salt         = sys.argv[4]&lt;br /&gt;
rounds       = sys.argv[5]&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_plenticore.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
PASSWD = credentials[&amp;quot;password&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
u       = randomString&lt;br /&gt;
&lt;br /&gt;
#u       = base64.b64encode(u.encode(&#039;utf-8&#039;)).decode(&#039;utf-8&#039;)&lt;br /&gt;
#print(&amp;quot;randomString: &amp;quot;,u)&lt;br /&gt;
&lt;br /&gt;
i       = nonce&lt;br /&gt;
o       = int(rounds)&lt;br /&gt;
a       = salt&lt;br /&gt;
bitSalt = base64.b64decode(a)&lt;br /&gt;
&lt;br /&gt;
#print(&amp;quot;nonce       : &amp;quot;,i)&lt;br /&gt;
#print(&amp;quot;salt        : &amp;quot;,a)&lt;br /&gt;
#print(&amp;quot;rounds      : &amp;quot;,o)&lt;br /&gt;
&lt;br /&gt;
def getPBKDF2Hash(password, bytedSalt, rounds):&lt;br /&gt;
    return hashlib.pbkdf2_hmac(&#039;sha256&#039;, password.encode(&#039;utf-8&#039;), bytedSalt, rounds)&lt;br /&gt;
&lt;br /&gt;
r = getPBKDF2Hash(PASSWD,bitSalt,o)&lt;br /&gt;
s = hmac.new(r, &amp;quot;Client Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
c = hmac.new(r, &amp;quot;Server Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
_ = hashlib.sha256(s).digest()&lt;br /&gt;
d = &amp;quot;n=user,r=&amp;quot;+u+&amp;quot;,r=&amp;quot;+i+&amp;quot;,s=&amp;quot;+a+&amp;quot;,i=&amp;quot;+str(o)+&amp;quot;,c=biws,r=&amp;quot;+i&lt;br /&gt;
g = hmac.new(_, d.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
p = hmac.new(c, d.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
f = bytes(a ^ b for (a, b) in zip(s, g))&lt;br /&gt;
proof = base64.b64encode(f).decode(&#039;utf-8&#039;)&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_fhem.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
fh = fhem.Fhem(web, protocol=&amp;quot;http&amp;quot;, port=8083, username=credentials[&amp;quot;username&amp;quot;], password=credentials[&amp;quot;password&amp;quot;])&lt;br /&gt;
&lt;br /&gt;
fh.send_cmd(&amp;quot;setreading PV_Anlage_1_API auth_proof &amp;quot; + proof)&lt;br /&gt;
&lt;br /&gt;
#print(&amp;quot;proof       : &amp;quot;,proof)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====== plenticore_auth_session ======&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ cat plenticore_auth_session.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import string&lt;br /&gt;
import base64&lt;br /&gt;
import hashlib&lt;br /&gt;
import os&lt;br /&gt;
import hmac&lt;br /&gt;
from Crypto.Cipher import AES&lt;br /&gt;
import binascii&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
import json&lt;br /&gt;
import fhem&lt;br /&gt;
&lt;br /&gt;
web          = sys.argv[1]&lt;br /&gt;
randomString = sys.argv[2]&lt;br /&gt;
nonce        = sys.argv[3]&lt;br /&gt;
salt         = sys.argv[4]&lt;br /&gt;
rounds       = sys.argv[5]&lt;br /&gt;
token        = sys.argv[6]&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_plenticore.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
PASSWD = credentials[&amp;quot;password&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
u       = randomString&lt;br /&gt;
i       = nonce&lt;br /&gt;
o       = int(rounds)&lt;br /&gt;
a       = salt&lt;br /&gt;
bitSalt = base64.b64decode(a)&lt;br /&gt;
&lt;br /&gt;
def getPBKDF2Hash(password, bytedSalt, rounds):&lt;br /&gt;
    return hashlib.pbkdf2_hmac(&#039;sha256&#039;, password.encode(&#039;utf-8&#039;), bytedSalt, rounds)&lt;br /&gt;
&lt;br /&gt;
r = getPBKDF2Hash(PASSWD,bitSalt,o)&lt;br /&gt;
&lt;br /&gt;
#print(&amp;quot;randomString: &amp;quot;,u)&lt;br /&gt;
#print(&amp;quot;nonce       : &amp;quot;,i)&lt;br /&gt;
#print(&amp;quot;salt        : &amp;quot;,a)&lt;br /&gt;
#print(&amp;quot;rounds      : &amp;quot;,o)&lt;br /&gt;
#print(&amp;quot;token       : &amp;quot;,token)&lt;br /&gt;
&lt;br /&gt;
s = hmac.new(r, &amp;quot;Client Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
_ = hashlib.sha256(s).digest()&lt;br /&gt;
d = &amp;quot;n=user,r=&amp;quot;+u+&amp;quot;,r=&amp;quot;+i+&amp;quot;,s=&amp;quot;+a+&amp;quot;,i=&amp;quot;+str(o)+&amp;quot;,c=biws,r=&amp;quot;+i&lt;br /&gt;
&lt;br /&gt;
y = hmac.new(_, &amp;quot;Session Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256)&lt;br /&gt;
y.update(d.encode(&#039;utf-8&#039;))&lt;br /&gt;
y.update(s)&lt;br /&gt;
P = y.digest()&lt;br /&gt;
protocol_key = P&lt;br /&gt;
t = os.urandom(16)&lt;br /&gt;
&lt;br /&gt;
e2          = AES.new(protocol_key,AES.MODE_GCM,t)&lt;br /&gt;
e2, authtag = e2.encrypt_and_digest(token.encode(&#039;utf-8&#039;))&lt;br /&gt;
&lt;br /&gt;
iv      = base64.b64encode(t).decode(&#039;utf-8&#039;)&lt;br /&gt;
authtag = base64.b64encode(authtag).decode(&amp;quot;utf-8&amp;quot;)&lt;br /&gt;
payload = base64.b64encode(e2).decode(&#039;utf-8&#039;)&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_fhem.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
fh = fhem.Fhem(web, protocol=&amp;quot;http&amp;quot;, port=8083, username=credentials[&amp;quot;username&amp;quot;], password=credentials[&amp;quot;password&amp;quot;])&lt;br /&gt;
&lt;br /&gt;
fh.send_cmd(&amp;quot;setreading PV_Anlage_1_API auth_iv &amp;quot; + iv)&lt;br /&gt;
fh.send_cmd(&amp;quot;setreading PV_Anlage_1_API auth_authtag &amp;quot; + authtag)&lt;br /&gt;
fh.send_cmd(&amp;quot;setreading PV_Anlage_1_API auth_payload &amp;quot; + payload)&lt;br /&gt;
&lt;br /&gt;
#print(&amp;quot;iv          : &amp;quot;,iv)&lt;br /&gt;
#print(&amp;quot;authtag     : &amp;quot;,authtag)&lt;br /&gt;
#print(&amp;quot;payload     : &amp;quot;,payload)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablaufbeschreibung PV_Anlage_1_API ======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit dem ersten Aufruf und läuft dann vollautomatisch bis zur Rückgabe der auth_sessionId&lt;br /&gt;
   1. get PV_Anlage_1_API 01/auth/start&lt;br /&gt;
* auth_randomString64 - wird generiert&lt;br /&gt;
* /api/v1/auth/start - HTTP request erfolgt&lt;br /&gt;
* auth_nonce, auth_salt, auth_rounds werden empfangen&lt;br /&gt;
   2. auth_Step1_Message:auth_nonce.* wird getriggert&lt;br /&gt;
* plenticore_auth_finish.py wird ausgeführt&lt;br /&gt;
* auth_proof - wird berechnet&lt;br /&gt;
   3. auth_Step2_Message:auth_proof.* wird getriggert&lt;br /&gt;
* Start von 02_/auth/finish&lt;br /&gt;
   4. get PV_Anlage_1_API 02_/auth/finish&lt;br /&gt;
* /api/v1/auth/finish - HTTP request erfolgt&lt;br /&gt;
* auth_signature, auth_token werden empfangen&lt;br /&gt;
   5. auth_Step3_Message:auth_token.* wird getriggert&lt;br /&gt;
* plenticore_auth_session.py wird ausgeführt&lt;br /&gt;
* auth_iv, auth_authtag, auth_payload - wird berechnet&lt;br /&gt;
   6. auth_Step4_Message:auth_payload.* wird getriggert&lt;br /&gt;
* Start von 03_/auth/session&lt;br /&gt;
   7. get PV_Anlage_1_API 03_/auth/session&lt;br /&gt;
* /api/v1/auth/session - HTTP request erfolgt&lt;br /&gt;
* auth_sessionId wird empfangen&lt;br /&gt;
&lt;br /&gt;
Bei allen folgenden HTTP requests wird nun die erhaltene auth_sessenId übermittelt.&lt;br /&gt;
&lt;br /&gt;
Bereits Implementierte Abfragen:&lt;br /&gt;
&lt;br /&gt;
get:&lt;br /&gt;
&lt;br /&gt;
start, finish, create_session werden für den Login benötigt und arbeiten über userreadings mit zwei Python Skripten zusammen&lt;br /&gt;
&lt;br /&gt;
01_/auth/start&lt;br /&gt;
&lt;br /&gt;
02_/auth/finish&lt;br /&gt;
&lt;br /&gt;
03_/auth/create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand, es muss aber kurz vorher abgefragt werden&lt;br /&gt;
&lt;br /&gt;
04_/auth/me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
&lt;br /&gt;
05_/info/version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
&lt;br /&gt;
20_/processdata/scb_statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit attr &amp;lt;Device&amp;gt; showBody 1 angezeigt werden kann.&lt;br /&gt;
&lt;br /&gt;
21_/modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
&lt;br /&gt;
24_/logdata/download&lt;br /&gt;
&lt;br /&gt;
Speicher Typen wurden folgende ermittelt 0=keine , 4=BYD&lt;br /&gt;
&lt;br /&gt;
Diese Abfragewerte können auch gesetzt werden, siehe set Befehle&lt;br /&gt;
&lt;br /&gt;
31_Battery_Type&lt;br /&gt;
&lt;br /&gt;
32_Battery_MinHomeComsumption&lt;br /&gt;
&lt;br /&gt;
33_Battery_Strategy&lt;br /&gt;
&lt;br /&gt;
34_Battery_MinSoc&lt;br /&gt;
&lt;br /&gt;
35_Battery_SmartBatteryControl_Enable&lt;br /&gt;
&lt;br /&gt;
36_Battery_DynamicSoc_Enable&lt;br /&gt;
&lt;br /&gt;
Das zeigt den FW Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
&lt;br /&gt;
41_/update/status&lt;br /&gt;
&lt;br /&gt;
set:&lt;br /&gt;
&lt;br /&gt;
Eine bestehende Session wird abgemeldet&lt;br /&gt;
&lt;br /&gt;
06_/auth/logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
&lt;br /&gt;
23_/events/latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
&lt;br /&gt;
31_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
32_Battery_MinHomeComsumption&lt;br /&gt;
&lt;br /&gt;
33_Battery_Strategy&lt;br /&gt;
&lt;br /&gt;
34_Battery_MinSoc&lt;br /&gt;
&lt;br /&gt;
35_Battery_SmartBatteryControl_Enable&lt;br /&gt;
&lt;br /&gt;
36_Battery_DynamicSoc_Enable&lt;br /&gt;
&lt;br /&gt;
Der Reboot läuft noch nicht. Da ist die API ziemlich zickig. Ich habe jedoch bereits ein Skript, womit es geht :-)&lt;br /&gt;
&lt;br /&gt;
51_/system/reboot&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch eine Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
====== RAW Definition des PV_Anlage_1_API ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Anlage_1_API HTTPMOD http://%IP-Address_Plenticore%/api/v1/auth/me 0&lt;br /&gt;
&lt;br /&gt;
attr PV_Anlage_1_API DbLogExclude .*&lt;br /&gt;
attr PV_Anlage_1_API DbLogInclude Statistic_Autarky.*,Statistic_Energy.*,Statistic_Own.*,Statistic_Total.*,Statistic_Yield.*,Statistic_PV.*,Statistic_Grid.*&lt;br /&gt;
attr PV_Anlage_1_API comment Version 2020.10.23 11:03&lt;br /&gt;
attr PV_Anlage_1_API enableControlSet 0&lt;br /&gt;
attr PV_Anlage_1_API enableCookies 1&lt;br /&gt;
attr PV_Anlage_1_API get01Data {&amp;quot;nonce&amp;quot;: &amp;quot;%randomString64%&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API get01Name 01_/auth/start&lt;br /&gt;
attr PV_Anlage_1_API get01URL http://%IP-Address_Plenticore%/api/v1/auth/start&lt;br /&gt;
attr PV_Anlage_1_API get02-1Name auth_signature&lt;br /&gt;
attr PV_Anlage_1_API get02-2Name auth_token&lt;br /&gt;
attr PV_Anlage_1_API get02Data {&amp;quot;transactionId&amp;quot;: &amp;quot;%auth_transactionId%&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;%auth_proof%&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API get02JSON .&lt;br /&gt;
attr PV_Anlage_1_API get02Name 02_/auth/finish&lt;br /&gt;
attr PV_Anlage_1_API get02URL http://%IP-Address_Plenticore%/api/v1/auth/finish&lt;br /&gt;
attr PV_Anlage_1_API get03Data {&amp;quot;transactionId&amp;quot;: &amp;quot;%auth_transactionId%&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;%auth_iv%&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;%auth_authtag%&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;%auth_payload%&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API get03Name 03_/auth/create_session&lt;br /&gt;
attr PV_Anlage_1_API get03URL http://%IP-Address_Plenticore%/api/v1/auth/create_session&lt;br /&gt;
attr PV_Anlage_1_API get04-1Name auth_me_active&lt;br /&gt;
attr PV_Anlage_1_API get04-2Name auth_me_locked&lt;br /&gt;
attr PV_Anlage_1_API get04-3Name auth_me_authenticated&lt;br /&gt;
attr PV_Anlage_1_API get04-4Name auth_me_anonymous&lt;br /&gt;
attr PV_Anlage_1_API get04-5Name auth_me_role&lt;br /&gt;
attr PV_Anlage_1_API get04-6Name auth_me_permissions&lt;br /&gt;
attr PV_Anlage_1_API get04Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get04JSON .&lt;br /&gt;
attr PV_Anlage_1_API get04Name 04_/auth/me&lt;br /&gt;
attr PV_Anlage_1_API get04URL http://%IP-Address_Plenticore%/api/v1/auth/me&lt;br /&gt;
attr PV_Anlage_1_API get05-1Name info_name&lt;br /&gt;
attr PV_Anlage_1_API get05-2Name info_api_version&lt;br /&gt;
attr PV_Anlage_1_API get05-3Name info_sw_version&lt;br /&gt;
attr PV_Anlage_1_API get05-4Name info_hostname&lt;br /&gt;
attr PV_Anlage_1_API get05JSON .&lt;br /&gt;
attr PV_Anlage_1_API get05Name 05_/info/version&lt;br /&gt;
attr PV_Anlage_1_API get05URL http://%IP-Address_Plenticore%/api/v1/info/version&lt;br /&gt;
attr PV_Anlage_1_API get20-10Name Statistic_EnergyHome_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-11Name Statistic_EnergyHome_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-12Name Statistic_EnergyHome_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-13Name Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-14Name Statistic_EnergyHomeBat_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-15Name Statistic_EnergyHomeBat_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-16Name Statistic_EnergyHomeBat_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-17Name Statistic_EnergyHomeGrid_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-18Name Statistic_EnergyHomeGrid_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-19Name Statistic_EnergyHomeGrid_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-1Name Statistic_Autarky_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-20Name Statistic_EnergyHomeGrid_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-21Name Statistic_EnergyHomePv_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-22Name Statistic_EnergyHomePv_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-23Name Statistic_EnergyHomePv_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-24Name Statistic_EnergyHomePv_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-25Name Statistic_OwnConsumptionRate_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-26Name Statistic_OwnConsumptionRate_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-27Name Statistic_OwnConsumptionRate_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-28Name Statistic_OwnConsumptionRate_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-29Name Statistic_Yield_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-2Name Statistic_Autarky_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-30Name Statistic_Yield_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-31Name Statistic_Yield_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-32Name Statistic_Yield_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-3Name Statistic_Autarky_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-4Name Statistic_Autarky_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-5Name Statistic_CO2Saving_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-6Name Statistic_CO2Saving_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-7Name Statistic_CO2Saving_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-8Name Statistic_CO2Saving_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-9Name Statistic_EnergyHome_Day&lt;br /&gt;
attr PV_Anlage_1_API get20Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get20JSON 01_processdata_.._value&lt;br /&gt;
attr PV_Anlage_1_API get20Name 20_/processdata/scb_statistic_EnergyFlow&lt;br /&gt;
attr PV_Anlage_1_API get20URL http://%IP-Address_Plenticore%/api/v1/processdata/scb:statistic:EnergyFlow&lt;br /&gt;
attr PV_Anlage_1_API get21Name 21_/modules_list&lt;br /&gt;
attr PV_Anlage_1_API get21URL http://%IP-Address_Plenticore%/api/v1/modules&lt;br /&gt;
attr PV_Anlage_1_API get24Data {&amp;quot;end&amp;quot;:&amp;quot;%end_date%&amp;quot;,&amp;quot;begin&amp;quot;:&amp;quot;%begin_date%&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API get24Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get24Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get24Name 24_/logdata/download&lt;br /&gt;
attr PV_Anlage_1_API get24URL http://%IP-Address_Plenticore%/api/v1/logdata/download&lt;br /&gt;
attr PV_Anlage_1_API get31-1Name Battery_Type&lt;br /&gt;
attr PV_Anlage_1_API get31-2Name Battery_Type&lt;br /&gt;
attr PV_Anlage_1_API get31Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get31Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get31JSON .&lt;br /&gt;
attr PV_Anlage_1_API get31Name 31_Battery_Type&lt;br /&gt;
attr PV_Anlage_1_API get31URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:Type&lt;br /&gt;
attr PV_Anlage_1_API get32-1Name Battery_MinHomeComsumption&lt;br /&gt;
attr PV_Anlage_1_API get32-2Name Battery_MinHomeComsumption&lt;br /&gt;
attr PV_Anlage_1_API get32Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get32Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get32JSON .&lt;br /&gt;
attr PV_Anlage_1_API get32Name 32_Battery_MinHomeComsumption&lt;br /&gt;
attr PV_Anlage_1_API get32URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:MinHomeComsumption&lt;br /&gt;
attr PV_Anlage_1_API get33-1Name Battery_Strategy&lt;br /&gt;
attr PV_Anlage_1_API get33-2Name Battery_Strategy&lt;br /&gt;
attr PV_Anlage_1_API get33Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get33Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get33JSON .&lt;br /&gt;
attr PV_Anlage_1_API get33Name 33_Battery_Strategy&lt;br /&gt;
attr PV_Anlage_1_API get33URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:Strategy&lt;br /&gt;
attr PV_Anlage_1_API get34-1Name Battery_MinSoc&lt;br /&gt;
attr PV_Anlage_1_API get34-2Name Battery_MinSoc&lt;br /&gt;
attr PV_Anlage_1_API get34Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get34Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get34JSON .&lt;br /&gt;
attr PV_Anlage_1_API get34Name 34_Battery_MinSoc&lt;br /&gt;
attr PV_Anlage_1_API get34URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:MinSoc&lt;br /&gt;
attr PV_Anlage_1_API get35-1Name Battery_SmartBatteryControl_Enable&lt;br /&gt;
attr PV_Anlage_1_API get35-2Name Battery_SmartBatteryControl_Enable&lt;br /&gt;
attr PV_Anlage_1_API get35Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get35Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get35JSON .&lt;br /&gt;
attr PV_Anlage_1_API get35Name 35_Battery_SmartBatteryControl_Enable&lt;br /&gt;
attr PV_Anlage_1_API get35URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:SmartBatteryControl:Enable&lt;br /&gt;
attr PV_Anlage_1_API get36-1Name Battery_DynamicSoc_Enable&lt;br /&gt;
attr PV_Anlage_1_API get36-2Name Battery_DynamicSoc_Enable&lt;br /&gt;
attr PV_Anlage_1_API get36Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get36Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get36JSON .&lt;br /&gt;
attr PV_Anlage_1_API get36Name 36_Battery_DynamicSoc_Enable&lt;br /&gt;
attr PV_Anlage_1_API get36URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:DynamicSoc:Enable&lt;br /&gt;
attr PV_Anlage_1_API get41Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get41Name 41_/update/status&lt;br /&gt;
attr PV_Anlage_1_API get41URL http://%IP-Address_Plenticore%/api/v1/update/status&lt;br /&gt;
attr PV_Anlage_1_API getHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr PV_Anlage_1_API getHeader02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API group PV Eigenverbrauch&lt;br /&gt;
attr PV_Anlage_1_API icon sani_solar&lt;br /&gt;
attr PV_Anlage_1_API reading01-1Name auth_nonce&lt;br /&gt;
attr PV_Anlage_1_API reading01-2Name auth_rounds&lt;br /&gt;
attr PV_Anlage_1_API reading01-3Name auth_salt&lt;br /&gt;
attr PV_Anlage_1_API reading01-4Name auth_transactionId&lt;br /&gt;
attr PV_Anlage_1_API reading01JSON .&lt;br /&gt;
attr PV_Anlage_1_API reading02JSON sessionId&lt;br /&gt;
attr PV_Anlage_1_API reading02Name auth_sessionId&lt;br /&gt;
attr PV_Anlage_1_API reading0301JSON message&lt;br /&gt;
attr PV_Anlage_1_API reading0301Name info_message&lt;br /&gt;
attr PV_Anlage_1_API reading0302JSON error&lt;br /&gt;
attr PV_Anlage_1_API reading0302Name info_error&lt;br /&gt;
attr PV_Anlage_1_API replacement01Mode expression&lt;br /&gt;
attr PV_Anlage_1_API replacement01Regex %IP-Address_Plenticore%&lt;br /&gt;
attr PV_Anlage_1_API replacement01Value {ReadingsVal(&amp;quot;PV_Anlage_1_config&amp;quot;,&amp;quot;IP-Address_Plenticore&amp;quot;,&amp;quot;&amp;quot;)}&lt;br /&gt;
attr PV_Anlage_1_API replacement02Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement02Regex %auth_transactionId%&lt;br /&gt;
attr PV_Anlage_1_API replacement02Value auth_transactionId&lt;br /&gt;
attr PV_Anlage_1_API replacement03Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement03Regex %auth_proof%&lt;br /&gt;
attr PV_Anlage_1_API replacement03Value auth_proof&lt;br /&gt;
attr PV_Anlage_1_API replacement04Mode expression&lt;br /&gt;
attr PV_Anlage_1_API replacement04Regex %randomString64%&lt;br /&gt;
attr PV_Anlage_1_API replacement04Value {my $NAME = &amp;quot;PV_Anlage_1_API&amp;quot; ;;;;fhem(&amp;quot;deletereading &amp;quot;.$NAME.&amp;quot; message&amp;quot;);;;;fhem(&amp;quot;deletereading &amp;quot;.$NAME.&amp;quot; auth.*&amp;quot;);;;;my @chars=(&#039;a&#039;..&#039;z&#039;,&#039;A&#039;..&#039;Z&#039;,&#039;0&#039;..&#039;9&#039;);; my $r;; foreach(1..16) {$r.=$chars[rand @chars];;};;;; fhem(&amp;quot;setreading &amp;quot;.$NAME.&amp;quot; auth_randomString64 &amp;quot;.$r);;;; $r;;;;}&lt;br /&gt;
attr PV_Anlage_1_API replacement05Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement05Regex %auth_randomString64%&lt;br /&gt;
attr PV_Anlage_1_API replacement05Value auth_randomString64&lt;br /&gt;
attr PV_Anlage_1_API replacement06Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement06Regex %auth_token%&lt;br /&gt;
attr PV_Anlage_1_API replacement06Value auth_token&lt;br /&gt;
attr PV_Anlage_1_API replacement07Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement07Regex %auth_signature%&lt;br /&gt;
attr PV_Anlage_1_API replacement07Value auth_signature&lt;br /&gt;
attr PV_Anlage_1_API replacement08Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement08Regex %auth_authtag%&lt;br /&gt;
attr PV_Anlage_1_API replacement08Value auth_authtag&lt;br /&gt;
attr PV_Anlage_1_API replacement09Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement09Regex %auth_payload%&lt;br /&gt;
attr PV_Anlage_1_API replacement09Value auth_payload&lt;br /&gt;
attr PV_Anlage_1_API replacement10Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement10Regex %auth_iv%&lt;br /&gt;
attr PV_Anlage_1_API replacement10Value auth_iv&lt;br /&gt;
attr PV_Anlage_1_API replacement11Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement11Regex %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API replacement11Value auth_sessionId&lt;br /&gt;
attr PV_Anlage_1_API replacement12Mode expression&lt;br /&gt;
attr PV_Anlage_1_API replacement12Regex %begin_date%&lt;br /&gt;
attr PV_Anlage_1_API replacement12Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr PV_Anlage_1_API replacement13Mode expression&lt;br /&gt;
attr PV_Anlage_1_API replacement13Regex %end_date%&lt;br /&gt;
attr PV_Anlage_1_API replacement13Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr PV_Anlage_1_API room Strom-&amp;gt;Energie,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Anlage_1_API set06Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set06Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set06Method POST&lt;br /&gt;
attr PV_Anlage_1_API set06Name 06_/auth/logout&lt;br /&gt;
attr PV_Anlage_1_API set06NoArg 1&lt;br /&gt;
attr PV_Anlage_1_API set06URL http://%IP-Address_Plenticore%/api/v1/auth/logout&lt;br /&gt;
attr PV_Anlage_1_API set23-10Name Event_02_code&lt;br /&gt;
attr PV_Anlage_1_API set23-11Name Event_02_description&lt;br /&gt;
attr PV_Anlage_1_API set23-12Name Event_02_end_time&lt;br /&gt;
attr PV_Anlage_1_API set23-13Name Event_02_group&lt;br /&gt;
attr PV_Anlage_1_API set23-14Name Event_02_is_active&lt;br /&gt;
attr PV_Anlage_1_API set23-15Name Event_02_long_description&lt;br /&gt;
attr PV_Anlage_1_API set23-16Name Event_02_start_time&lt;br /&gt;
attr PV_Anlage_1_API set23-17Name Event_03_category&lt;br /&gt;
attr PV_Anlage_1_API set23-18Name Event_03_code&lt;br /&gt;
attr PV_Anlage_1_API set23-19Name Event_03_description&lt;br /&gt;
attr PV_Anlage_1_API set23-1Name Event_01_category&lt;br /&gt;
attr PV_Anlage_1_API set23-20Name Event_03_end_time&lt;br /&gt;
attr PV_Anlage_1_API set23-21Name Event_03_group&lt;br /&gt;
attr PV_Anlage_1_API set23-22Name Event_03_is_active&lt;br /&gt;
attr PV_Anlage_1_API set23-23Name Event_03_long_description&lt;br /&gt;
attr PV_Anlage_1_API set23-24Name Event_03_start_time&lt;br /&gt;
attr PV_Anlage_1_API set23-25Name Event_04_category&lt;br /&gt;
attr PV_Anlage_1_API set23-26Name Event_04_code&lt;br /&gt;
attr PV_Anlage_1_API set23-27Name Event_04_description&lt;br /&gt;
attr PV_Anlage_1_API set23-28Name Event_04_end_time&lt;br /&gt;
attr PV_Anlage_1_API set23-29Name Event_04_group&lt;br /&gt;
attr PV_Anlage_1_API set23-2Name Event_01_code&lt;br /&gt;
attr PV_Anlage_1_API set23-30Name Event_04_is_active&lt;br /&gt;
attr PV_Anlage_1_API set23-31Name Event_04_long_description&lt;br /&gt;
attr PV_Anlage_1_API set23-32Name Event_04_start_time&lt;br /&gt;
attr PV_Anlage_1_API set23-33Name Event_05_category&lt;br /&gt;
attr PV_Anlage_1_API set23-34Name Event_05_code&lt;br /&gt;
attr PV_Anlage_1_API set23-35Name Event_05_description&lt;br /&gt;
attr PV_Anlage_1_API set23-36Name Event_05_end_time&lt;br /&gt;
attr PV_Anlage_1_API set23-37Name Event_05_group&lt;br /&gt;
attr PV_Anlage_1_API set23-38Name Event_05_is_active&lt;br /&gt;
attr PV_Anlage_1_API set23-39Name Event_05_long_description&lt;br /&gt;
attr PV_Anlage_1_API set23-3Name Event_01_description&lt;br /&gt;
attr PV_Anlage_1_API set23-40Name Event_05_start_time&lt;br /&gt;
attr PV_Anlage_1_API set23-4Name Event_01_end_time&lt;br /&gt;
attr PV_Anlage_1_API set23-5Name Event_01_group&lt;br /&gt;
attr PV_Anlage_1_API set23-6Name Event_01_is_active&lt;br /&gt;
attr PV_Anlage_1_API set23-7Name Event_01_long_description&lt;br /&gt;
attr PV_Anlage_1_API set23-8Name Event_01_start_time&lt;br /&gt;
attr PV_Anlage_1_API set23-9Name Event_02_category&lt;br /&gt;
attr PV_Anlage_1_API set23Data {&amp;quot;max&amp;quot;:5,&amp;quot;language&amp;quot;:&amp;quot;$val&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API set23Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set23Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set23Hint en-gb,de-de&lt;br /&gt;
attr PV_Anlage_1_API set23JSON .&lt;br /&gt;
attr PV_Anlage_1_API set23Name 23_/events/latest_5&lt;br /&gt;
attr PV_Anlage_1_API set23ParseResponse 1&lt;br /&gt;
attr PV_Anlage_1_API set23TextArg 1&lt;br /&gt;
attr PV_Anlage_1_API set23URL http://%IP-Address_Plenticore%/api/v1/events/latest&lt;br /&gt;
attr PV_Anlage_1_API set31Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:Type&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr PV_Anlage_1_API set31Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set31Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set31Hint 0,4&lt;br /&gt;
attr PV_Anlage_1_API set31Method PUT&lt;br /&gt;
attr PV_Anlage_1_API set31Name 31_Battery_Type&lt;br /&gt;
attr PV_Anlage_1_API set31URL http://%IP-Address_Plenticore%/api/v1/settings&lt;br /&gt;
attr PV_Anlage_1_API set33Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:Strategy&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr PV_Anlage_1_API set33Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set33Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set33Hint 1,2&lt;br /&gt;
attr PV_Anlage_1_API set33Method PUT&lt;br /&gt;
attr PV_Anlage_1_API set33Name 31_Battery_Strategy&lt;br /&gt;
attr PV_Anlage_1_API set33URL http://%IP-Address_Plenticore%/api/v1/settings&lt;br /&gt;
attr PV_Anlage_1_API set34Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:MinSoc&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr PV_Anlage_1_API set34Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set34Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set34Hint slider,10,5,100&lt;br /&gt;
attr PV_Anlage_1_API set34Method PUT&lt;br /&gt;
attr PV_Anlage_1_API set34Name 34_Battery_MinSoc&lt;br /&gt;
attr PV_Anlage_1_API set34URL http://%IP-Address_Plenticore%/api/v1/settings&lt;br /&gt;
attr PV_Anlage_1_API set35Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:SmartBatteryControl:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr PV_Anlage_1_API set35Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set35Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set35Hint 0,1&lt;br /&gt;
attr PV_Anlage_1_API set35Method PUT&lt;br /&gt;
attr PV_Anlage_1_API set35Name 35_SmartBatteryControl_Enable&lt;br /&gt;
attr PV_Anlage_1_API set35URL http://%IP-Address_Plenticore%/api/v1/settings&lt;br /&gt;
attr PV_Anlage_1_API set51Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set51Header02 Accept: application/json, Connection: keep-alive, Content-type: application/json&lt;br /&gt;
attr PV_Anlage_1_API set51Method Post&lt;br /&gt;
attr PV_Anlage_1_API set51Name 51_/system/reboot&lt;br /&gt;
attr PV_Anlage_1_API set51NoArg 1&lt;br /&gt;
attr PV_Anlage_1_API set51URL http://%IP-Address_Plenticore%/api/v1/system/reboot&lt;br /&gt;
attr PV_Anlage_1_API showBody 1&lt;br /&gt;
attr PV_Anlage_1_API showError 1&lt;br /&gt;
attr PV_Anlage_1_API sortby 02&lt;br /&gt;
attr PV_Anlage_1_API stateFormat {\&lt;br /&gt;
 my $calcVal=0;;\&lt;br /&gt;
\&lt;br /&gt;
 my $pvt   = sprintf(&amp;quot;%04d W&amp;quot;,ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_AC_active_power&amp;quot;,&amp;quot;&amp;quot;) );;\&lt;br /&gt;
 my $pvtd  = sprintf(&amp;quot;%05.2f kWh&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;, &amp;quot;&amp;quot;)/1000 );;\&lt;br /&gt;
 my $pvtm  = sprintf(&amp;quot;%06.2f kWh&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;, &amp;quot;&amp;quot;)/1000 );;\&lt;br /&gt;
 my $pvty  = sprintf(&amp;quot;%08.2f kWh&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;, &amp;quot;&amp;quot;)/1000 );;\&lt;br /&gt;
\&lt;br /&gt;
 my $pv  = sprintf(&amp;quot;%04d W&amp;quot;,ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_battery&amp;quot;, &amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_PV&amp;quot;, &amp;quot;&amp;quot;) );;\&lt;br /&gt;
 my $pvd  = sprintf(&amp;quot;%05.2f kWh&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyHomePvSum_Day&amp;quot;, &amp;quot;&amp;quot;)/1000 );;\&lt;br /&gt;
 my $pvm  = sprintf(&amp;quot;%06.2f kWh&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyHomePvSum_Month&amp;quot;, &amp;quot;&amp;quot;)/1000 );;\&lt;br /&gt;
 my $pvy  = sprintf(&amp;quot;%08.2f kWh&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyHomePvSum_Year&amp;quot;, &amp;quot;&amp;quot;)/1000 );;\&lt;br /&gt;
\&lt;br /&gt;
 my $gfi  =  sprintf(&amp;quot;%04d W&amp;quot;,(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0)&amp;lt;=0 ? abs(round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0),0)):  0) );;\&lt;br /&gt;
 my $gfid = sprintf(&amp;quot;%05.2f kWh&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyFeedInGrid_Day&amp;quot;, &amp;quot;&amp;quot;)/1000 );;\&lt;br /&gt;
 my $gfim = sprintf(&amp;quot;%06.2f kWh&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyFeedInGrid_Month&amp;quot;, &amp;quot;&amp;quot;)/1000 );;\&lt;br /&gt;
 my $gfiy = sprintf(&amp;quot;%08.2f kWh&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyFeedInGrid_Year&amp;quot;, &amp;quot;&amp;quot;)/1000 );;\&lt;br /&gt;
\&lt;br /&gt;
 my $eb   = sprintf(&amp;quot;%04d W&amp;quot;,(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0)&amp;gt;=0 ? round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0),0) : 0) );;\&lt;br /&gt;
 my $ebd  = sprintf(&amp;quot;%05.2f kWh&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Day&amp;quot;, &amp;quot;&amp;quot;)/1000 );;\&lt;br /&gt;
 my $ebm  = sprintf(&amp;quot;%06.2f kWh&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Month&amp;quot;, &amp;quot;&amp;quot;)/1000 );;\&lt;br /&gt;
 my $eby  = sprintf(&amp;quot;%08.2f kWh&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Year&amp;quot;, &amp;quot;&amp;quot;)/1000 );;\&lt;br /&gt;
\&lt;br /&gt;
 my $et   = sprintf(&amp;quot;%04d W&amp;quot;,(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_PV&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_battery&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_grid&amp;quot;,&amp;quot;&amp;quot;)) );;\&lt;br /&gt;
 my $etd  = sprintf(&amp;quot;%05.2f kWh&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_TotalConsumption_Day&amp;quot;, &amp;quot;&amp;quot;)/1000 );;\&lt;br /&gt;
 my $etm  = sprintf(&amp;quot;%06.2f kWh&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_TotalConsumption_Month&amp;quot;, &amp;quot;&amp;quot;)/1000 );;\&lt;br /&gt;
 my $ety  = sprintf(&amp;quot;%08.2f kWh&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_TotalConsumption_Year&amp;quot;, &amp;quot;&amp;quot;)/1000 );;\&lt;br /&gt;
\&lt;br /&gt;
 my $valA = ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;, &amp;quot;Total_AC_active_power&amp;quot;,&amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;, &amp;quot;Home_own_consumption_from_grid&amp;quot;,&amp;quot;&amp;quot;);;\&lt;br /&gt;
    $calcVal = ($valA &amp;gt; 0) ? round($valA /($valA + ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;, &amp;quot;Home_own_consumption_from_grid&amp;quot;,&amp;quot;&amp;quot;))*100 ,0) : 0;;\&lt;br /&gt;
 my $aq = sprintf(&amp;quot;%3.0f %%&amp;quot;,(($calcVal &amp;gt; 100) ? 100 : $calcVal) );;\&lt;br /&gt;
 \&lt;br /&gt;
 my $aqd  = sprintf(&amp;quot;%3.0f %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_Autarky_Day&amp;quot;, &amp;quot;&amp;quot;) );;\&lt;br /&gt;
 my $aqm  = sprintf(&amp;quot;%3.0f %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_Autarky_Month&amp;quot;, &amp;quot;&amp;quot;) );;\&lt;br /&gt;
 my $aqy  = sprintf(&amp;quot;%3.0f %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_Autarky_Year&amp;quot;, &amp;quot;&amp;quot;) );;\&lt;br /&gt;
 \&lt;br /&gt;
 my $valS = ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_AC_active_power&amp;quot;, 0);;\&lt;br /&gt;
    $calcVal = ($valS &amp;gt; 0) ? round((ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_PV&amp;quot;, &amp;quot;0&amp;quot;) + ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_battery&amp;quot;,&amp;quot;0&amp;quot;)) / $valS * 100 ,0) : 0;;\&lt;br /&gt;
 my $sq   =  sprintf(&amp;quot;%3.0f %%&amp;quot;,(($calcVal &amp;gt; 100) ? 100 : $calcVal) );;\&lt;br /&gt;
\&lt;br /&gt;
 my $sqd  = sprintf(&amp;quot;%3.0f %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_OwnConsumptionRate_Day&amp;quot;, &amp;quot;&amp;quot;) );;\&lt;br /&gt;
 my $sqm  = sprintf(&amp;quot;%3.0f %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_OwnConsumptionRate_Month&amp;quot;, &amp;quot;&amp;quot;) );;\&lt;br /&gt;
 my $sqy  = sprintf(&amp;quot;%3.0f %%&amp;quot;,ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;Statistic_OwnConsumptionRate_Year&amp;quot;, &amp;quot;&amp;quot;) );;\&lt;br /&gt;
\&lt;br /&gt;
 my $md   = ReadingsTimestamp(&amp;quot;$name&amp;quot;, &amp;quot;auth_me_authenticated&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
 my $cd   = ReadingsTimestamp(&amp;quot;$name&amp;quot;, &amp;quot;Statistic_Autarky_Day&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
 my $cm   = ReadingsTimestamp(&amp;quot;$name&amp;quot;, &amp;quot;Statistic_Autarky_Month&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
 my $cy   = ReadingsTimestamp(&amp;quot;$name&amp;quot;, &amp;quot;Statistic_Autarky_Year&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt; &amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;aktueller Wert&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;Heute&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;dieser Monat&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;dieses Jahr&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;PV-Erzeugung-Total&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvt.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvtd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvtm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvty.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;PV-Einspeisung&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$gfi.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$gfid.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$gfim.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$gfiy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Netz-Bezug&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$eb.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$ebd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$ebm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$eby.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;PV-Bezug&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pv.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Energieverbrauch&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$et.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$etd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$etm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$ety.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Autarkiequote&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$aq.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$aqd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$aqm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$aqy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Eigenverbrauchsquote&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$sq.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$sqd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$sqm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$sqy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Berechnung am&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$md.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$cd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$cm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$cy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;/table&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr PV_Anlage_1_API timeout 7&lt;br /&gt;
attr PV_Anlage_1_API userReadings auth_first_called:auth_randomString64.* {my $first_called = InternalVal(&amp;quot;$NAME&amp;quot;,&amp;quot;path&amp;quot;,&amp;quot;n.a&amp;quot;);;;; $first_called =~ s/:/_/g;;;;$first_called ;;;;$first_called =~ s/\/api\/v1//g;;;; my %replace = (&amp;quot;/auth/me&amp;quot; =&amp;gt; &amp;quot;04_/auth/me&amp;quot;,&amp;quot;/info/version&amp;quot; =&amp;gt; &amp;quot;05_/info/version&amp;quot;,&amp;quot;/processdata/scb_statistic_EnergyFlow&amp;quot; =&amp;gt; &amp;quot;20_/processdata/scb_statistic_EnergyFlow&amp;quot;,&amp;quot;/modules_list&amp;quot; =&amp;gt; &amp;quot;21_/modules_list&amp;quot;,&amp;quot;/logdata/download&amp;quot; =&amp;gt; &amp;quot;24_/logdata/download&amp;quot;,&amp;quot;/update/status&amp;quot; =&amp;gt; &amp;quot;41_/update/status&amp;quot;,&amp;quot;/system/reboot&amp;quot; =&amp;gt; &amp;quot;04_/auth/me&amp;quot;,);;;; $replace{$first_called};;;;},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step1_Message:auth_transactionId.* {system(&amp;quot;/usr/bin/python3 /opt/fhem/python/bin/plenticore_auth_finish.py &amp;quot;.ReadingsVal(&amp;quot;PV_Anlage_1_config&amp;quot;,&amp;quot;IP-Address_FHEM&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;29000&amp;quot;).&amp;quot; &amp;amp;&amp;quot;);;;; &amp;quot;Prepare auth_finish started with auth_nonce &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;)},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step2_Message:auth_proof.* { fhem(&amp;quot;get &amp;quot;.$NAME.&amp;quot; 02_/auth/finish&amp;quot;) ;;;; &amp;quot;HTTP Request 02_/auth/finish with auth_proof &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_proof&amp;quot;,&amp;quot;&amp;quot;)},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step3_Message:auth_token.* {system(&amp;quot;/usr/bin/python3 /opt/fhem/python/bin/plenticore_auth_session.py &amp;quot;.ReadingsVal(&amp;quot;PV_Anlage_1_config&amp;quot;,&amp;quot;IP-Address_FHEM&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;amp;&amp;quot;);;;; &amp;quot;Prepare auth_session started with auth_token &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;&amp;quot;)},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step4_Message:auth_payload.* { fhem(&amp;quot;get &amp;quot;.$NAME.&amp;quot; 03_/auth/create_session&amp;quot;) ;;;; &amp;quot;HTTP Request 03_/auth/create_session with auth_authtag &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_authtag&amp;quot;,&amp;quot;&amp;quot;)},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step5_Message:auth_sessionId.* {my $restack = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_first_called&amp;quot;,&amp;quot;&amp;quot;) ;;;; ($restack ne &amp;quot;&amp;quot;)?fhem(&amp;quot;get &amp;quot;.$NAME.&amp;quot; &amp;quot;.$restack):&amp;quot;No further HTTP request&amp;quot;;;;;},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyHomePvSum_Day:Statistic_EnergyHomePv_Day.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;, &amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;, &amp;quot;&amp;quot;)) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyHomePvSum_Month:Statistic_EnergyHomePv_Month.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;, &amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;, &amp;quot;&amp;quot;)) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyHomePvSum_Year:Statistic_EnergyHomePv_Year.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;, &amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;, &amp;quot;&amp;quot;)) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyFeedInGrid_Day:Statistic_Yield_Day.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;, &amp;quot;0&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;, &amp;quot;&amp;quot;)),2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyFeedInGrid_Month:Statistic_Yield_Month.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;, &amp;quot;0&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;, &amp;quot;&amp;quot;)),2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_EnergyFeedInGrid_Year:Statistic_Yield_Year.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;, &amp;quot;0&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;, &amp;quot;&amp;quot;)),2)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
Statistic_TotalConsumption_Day:Statistic_EnergyHomePv_Day.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Day&amp;quot;,&amp;quot;&amp;quot;) ) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_TotalConsumption_Month:Statistic_EnergyHomePv_Month.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Month&amp;quot;,&amp;quot;&amp;quot;) ) ,2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_TotalConsumption_Year:Statistic_EnergyHomePv_Year.* {round( (ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Year&amp;quot;,&amp;quot;&amp;quot;) ),2)},\&lt;br /&gt;
\&lt;br /&gt;
\&lt;br /&gt;
Statistic_Yield_NoBat_Day:Statistic_Yield_Day.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;, &amp;quot;0&amp;quot;)),2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_Yield_NoBat_Month:Statistic_Yield_Month.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;, &amp;quot;0&amp;quot;)),2)},\&lt;br /&gt;
\&lt;br /&gt;
Statistic_Yield_NoBat_Year:Statistic_Yield_Year.* {round((ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;, &amp;quot;0&amp;quot;)),2)}&lt;br /&gt;
attr PV_Anlage_1_API verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kostal Smart Energy Manager (KSEM) (Modbus/TCP) ===&lt;br /&gt;
Diese Einbindung ist nicht zwingend notwendig, jedoch weil es möglich ist hier beschrieben.&lt;br /&gt;
Das Gerät ist hier mit &amp;quot;disable 1&amp;quot; konfiguriert, um es zu verwenden muss das Attribut auf 0 gesetzt oder einfach gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist noch komplett deaktiviert, weshalb man seine Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_KSEM ModbusAttr 1 60 &amp;lt;IP-Address_KSEM&amp;gt;:502 TCP&lt;br /&gt;
attr PV_KSEM DbLogExclude .*&lt;br /&gt;
attr PV_KSEM alias PV_Energy_Manager&lt;br /&gt;
attr PV_KSEM dev-h-defPoll 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Current-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Current_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Current-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Current-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Current-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Freq-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Freq_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Freq-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Freq-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Freq-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_PF-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_PF_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_PF-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_PF-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_PF-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Power-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Power_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Power-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Power-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Power-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VA-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VA_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VA-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VA-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VA-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VAR-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VAR_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VAR-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VAR-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VAR-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Voltage-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Voltage_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Voltage-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Voltage-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Voltage-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-STR32-expr $val =~ s/[\00]+//gr&lt;br /&gt;
attr PV_KSEM dev-type-STR32-format %s&lt;br /&gt;
attr PV_KSEM dev-type-STR32-len 16&lt;br /&gt;
attr PV_KSEM dev-type-STR32-unpack a*&lt;br /&gt;
attr PV_KSEM dev-type-UINT16-format %s&lt;br /&gt;
attr PV_KSEM dev-type-UINT16-len 1&lt;br /&gt;
attr PV_KSEM dev-type-UINT32-format %s&lt;br /&gt;
attr PV_KSEM dev-type-UINT32-len 2&lt;br /&gt;
attr PV_KSEM dev-type-UINT64-expr $val/10000&lt;br /&gt;
attr PV_KSEM dev-type-UINT64-format %s&lt;br /&gt;
attr PV_KSEM dev-type-UINT64-len 4&lt;br /&gt;
attr PV_KSEM dev-type-UINT64-unpack Q&amp;gt;&lt;br /&gt;
attr PV_KSEM disable 1&lt;br /&gt;
attr PV_KSEM group PV Eigenverbrauch&lt;br /&gt;
attr PV_KSEM icon measure_power&lt;br /&gt;
attr PV_KSEM obj-h40072-reading M_AC_Current_A&lt;br /&gt;
attr PV_KSEM obj-h40072-type INT16_Current&lt;br /&gt;
attr PV_KSEM obj-h40073-reading M_AC_Current_B&lt;br /&gt;
attr PV_KSEM obj-h40073-type INT16_Current&lt;br /&gt;
attr PV_KSEM obj-h40074-reading M_AC_Current_C&lt;br /&gt;
attr PV_KSEM obj-h40074-type INT16_Current&lt;br /&gt;
attr PV_KSEM obj-h40075-reading M_AC_Current_SF&lt;br /&gt;
attr PV_KSEM obj-h40075-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40077-reading M_AC_Voltage_AN&lt;br /&gt;
attr PV_KSEM obj-h40077-type INT16_Voltage&lt;br /&gt;
attr PV_KSEM obj-h40078-reading M_AC_Voltage_BN&lt;br /&gt;
attr PV_KSEM obj-h40078-type INT16_Voltage&lt;br /&gt;
attr PV_KSEM obj-h40079-reading M_AC_Voltage_CN&lt;br /&gt;
attr PV_KSEM obj-h40079-type INT16_Voltage&lt;br /&gt;
attr PV_KSEM obj-h40084-reading M_AC_Voltage_SF&lt;br /&gt;
attr PV_KSEM obj-h40084-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40085-reading M_AC_Freq&lt;br /&gt;
attr PV_KSEM obj-h40085-type INT16_Freq&lt;br /&gt;
attr PV_KSEM obj-h40086-reading M_AC_Freq_SF&lt;br /&gt;
attr PV_KSEM obj-h40086-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40087-reading M_AC_Power&lt;br /&gt;
attr PV_KSEM obj-h40087-type INT16_Power&lt;br /&gt;
attr PV_KSEM obj-h40088-reading M_AC_Power_A&lt;br /&gt;
attr PV_KSEM obj-h40088-type INT16_Power&lt;br /&gt;
attr PV_KSEM obj-h40089-reading M_AC_Power_B&lt;br /&gt;
attr PV_KSEM obj-h40089-type INT16_Power&lt;br /&gt;
attr PV_KSEM obj-h40090-reading M_AC_Power_C&lt;br /&gt;
attr PV_KSEM obj-h40090-type INT16_Power&lt;br /&gt;
attr PV_KSEM obj-h40091-reading M_AC_Power_SF&lt;br /&gt;
attr PV_KSEM obj-h40091-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40092-reading M_AC_VA&lt;br /&gt;
attr PV_KSEM obj-h40092-type INT16_VA&lt;br /&gt;
attr PV_KSEM obj-h40093-reading M_AC_VA_A&lt;br /&gt;
attr PV_KSEM obj-h40093-type INT16_VA&lt;br /&gt;
attr PV_KSEM obj-h40094-reading M_AC_VA_B&lt;br /&gt;
attr PV_KSEM obj-h40094-type INT16_VA&lt;br /&gt;
attr PV_KSEM obj-h40095-reading M_AC_VA_C&lt;br /&gt;
attr PV_KSEM obj-h40095-type INT16_VA&lt;br /&gt;
attr PV_KSEM obj-h40096-reading M_AC_VA_SF&lt;br /&gt;
attr PV_KSEM obj-h40096-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40097-reading M_AC_VAR&lt;br /&gt;
attr PV_KSEM obj-h40097-type INT16_VAR&lt;br /&gt;
attr PV_KSEM obj-h40098-reading M_AC_VAR_A&lt;br /&gt;
attr PV_KSEM obj-h40098-type INT16_VAR&lt;br /&gt;
attr PV_KSEM obj-h40099-reading M_AC_VAR_B&lt;br /&gt;
attr PV_KSEM obj-h40099-type INT16_VAR&lt;br /&gt;
attr PV_KSEM obj-h40100-reading M_AC_VAR_C&lt;br /&gt;
attr PV_KSEM obj-h40100-type INT16_VAR&lt;br /&gt;
attr PV_KSEM obj-h40101-reading M_AC_VAR_SF&lt;br /&gt;
attr PV_KSEM obj-h40101-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40102-reading M_AC_PF&lt;br /&gt;
attr PV_KSEM obj-h40102-type INT16_PF&lt;br /&gt;
attr PV_KSEM obj-h40103-reading M_AC_PF_A&lt;br /&gt;
attr PV_KSEM obj-h40103-type INT16_PF&lt;br /&gt;
attr PV_KSEM obj-h40104-reading M_AC_PF_B&lt;br /&gt;
attr PV_KSEM obj-h40104-type INT16_PF&lt;br /&gt;
attr PV_KSEM obj-h40105-reading M_AC_PF_C&lt;br /&gt;
attr PV_KSEM obj-h40105-type INT16_PF&lt;br /&gt;
attr PV_KSEM obj-h40106-reading M_AC_PF_SF&lt;br /&gt;
attr PV_KSEM obj-h40106-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40108-reading M_Exported&lt;br /&gt;
attr PV_KSEM obj-h40108-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40110-reading M_Exported_A&lt;br /&gt;
attr PV_KSEM obj-h40110-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40112-reading M_Exported_B&lt;br /&gt;
attr PV_KSEM obj-h40112-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40114-reading M_Exported_C&lt;br /&gt;
attr PV_KSEM obj-h40114-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40116-reading M_Imported&lt;br /&gt;
attr PV_KSEM obj-h40116-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40118-reading M_Imported_A&lt;br /&gt;
attr PV_KSEM obj-h40118-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40120-reading M_Imported_B&lt;br /&gt;
attr PV_KSEM obj-h40120-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40122-reading M_Imported_C&lt;br /&gt;
attr PV_KSEM obj-h40122-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40125-reading M_Exported_VA&lt;br /&gt;
attr PV_KSEM obj-h40125-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40127-reading M_Exported_VA_A&lt;br /&gt;
attr PV_KSEM obj-h40127-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40129-reading M_Exported_VA_B&lt;br /&gt;
attr PV_KSEM obj-h40129-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40131-reading M_Exported_VA_C&lt;br /&gt;
attr PV_KSEM obj-h40131-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40133-reading M_Imported_VA&lt;br /&gt;
attr PV_KSEM obj-h40133-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40135-reading M_Imported_VA_A&lt;br /&gt;
attr PV_KSEM obj-h40135-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40137-reading M_Imported_VA_B&lt;br /&gt;
attr PV_KSEM obj-h40137-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40139-reading M_Imported_VA_C&lt;br /&gt;
attr PV_KSEM obj-h40139-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h512-reading Active_energy+&lt;br /&gt;
attr PV_KSEM obj-h512-type UINT64&lt;br /&gt;
attr PV_KSEM obj-h516-reading Active_energy-&lt;br /&gt;
attr PV_KSEM obj-h516-type UINT64&lt;br /&gt;
attr PV_KSEM obj-h8192-reading ManufacturerID&lt;br /&gt;
attr PV_KSEM obj-h8192-type UINT16&lt;br /&gt;
attr PV_KSEM obj-h8193-reading ProductID&lt;br /&gt;
attr PV_KSEM obj-h8193-type UINT16&lt;br /&gt;
attr PV_KSEM obj-h8194-reading ProductVersion&lt;br /&gt;
attr PV_KSEM obj-h8194-type UINT16&lt;br /&gt;
attr PV_KSEM obj-h8195-reading FirmwareVersion&lt;br /&gt;
attr PV_KSEM obj-h8195-type UINT16&lt;br /&gt;
attr PV_KSEM obj-h8196-reading VendorName&lt;br /&gt;
attr PV_KSEM obj-h8196-type STR32&lt;br /&gt;
attr PV_KSEM obj-h8212-reading Productname&lt;br /&gt;
attr PV_KSEM obj-h8212-type STR32&lt;br /&gt;
attr PV_KSEM obj-h8228-reading SerialNumber&lt;br /&gt;
attr PV_KSEM obj-h8228-type STR32&lt;br /&gt;
attr PV_KSEM obj-h8244-reading MeasuringInterval&lt;br /&gt;
attr PV_KSEM obj-h8244-type UINT16&lt;br /&gt;
attr PV_KSEM room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_KSEM sortby 05&lt;br /&gt;
attr PV_KSEM userReadings M_AC_Current:M_AC_Current_.* { ReadingsVal($NAME,&amp;quot;M_AC_Current_A&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_B&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_C&amp;quot;,0) }&lt;br /&gt;
attr PV_KSEM verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== BYD Speicher (mit HTTPMOD) ===&lt;br /&gt;
Diese Einbindung ist nicht zwingend notwendig.&lt;br /&gt;
Das Passwort steht momentan noch im userreading.&lt;br /&gt;
Durch einen Test von einem anderen Mitstreiter hat sich herausgestellt, dass BYD nun die neue Version des Speichers BYD_HVS ausliefert. Dieser neue Speicher hat anscheinend noch kein WebGui und wird nur über eine Handy App Konfiguriert. Leider kann man den somit nicht mit dieser Lösung abfragen.&lt;br /&gt;
Diese Speicher wird über das HTTPMOD Modul angesprochen, ist jedoch noch nicht bis in die letzten Tiefen abfragbar.&lt;br /&gt;
Der Begriff &amp;quot;Array&amp;quot; bezeichnet einen Speicher mit mehreren Modulen, die mit dem Series_Battery_Counts angegeben werden.&lt;br /&gt;
Eine Battery hat dabei ca. 1.28 KW&lt;br /&gt;
&lt;br /&gt;
Folge Besonderheiten bestehen noch bei dieser Implementierung:&lt;br /&gt;
 - Die Digest Key Erstellung erfolgt über userreading, die entsprechend der Reihenfolge getriggert werden.&lt;br /&gt;
 - Ein Login erfolgt nicht mit sid Definitionen&lt;br /&gt;
 - Um eine erstmalige Anmeldung durchzuführen, oder auch zwischendurch mal ein neues Login zu machen, löscht man die &amp;quot;auth_.*&amp;quot; readings.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
deletereading BYD_Status auth_.*&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 - Für die Anmeldung ruft man einfach mehrfach eine get Abfrage auf.&lt;br /&gt;
    * Beim ersten Aufruf sind die auth_* readings noch nicht vorhanden, oder auch eventuell falsch, wenn sie nicht gelöscht wurden.&lt;br /&gt;
    * Der zweite Aufruf aktualisiert dann nochmals die Digest Keys&lt;br /&gt;
    * Mit dem dritten Aufruf sind dann alle Keys ausgetauscht und die Anfrage wird bereits mit den Daten beantwortet&lt;br /&gt;
 - Für alle weiteren Abfragen besteht dann eine autorisierte Session mit der alle get Anfragen beantwortet werden.&lt;br /&gt;
 - Die Abfrage von RunData liefert im Standard Fall immer &amp;quot;Array Num 1&amp;quot; mit &amp;quot;Series Battery Num 1&amp;quot;. Dies kann leider noch nicht zur&lt;br /&gt;
   Abfrage der weiteren &amp;quot;Series Battery Num&amp;quot; umgeschaltet werden.&lt;br /&gt;
 - Achtung, die Abfrage von &amp;quot;StatisticInformation&amp;quot; ruft eine Tabelle mit 500 Ereignissen ab, von denen jedoch nur die aktuellsten 5&lt;br /&gt;
   als readings verarbeitet werden. Da aber alle 500 gelesen und verarbeitet werden müssen ist eine längere Laufzeit zu beachten.&lt;br /&gt;
   Aus diesem Grund sollte die &amp;quot;StatisticInformation&amp;quot; nicht in einem kurzen Zyklus erfolgen!&lt;br /&gt;
Implementiert sind derzeit:&lt;br /&gt;
 RunData&lt;br /&gt;
 InstallationConfig&lt;br /&gt;
 DeviceInformation&lt;br /&gt;
 BatteryInformation&lt;br /&gt;
 StatisticInformation&lt;br /&gt;
&lt;br /&gt;
userreading:&lt;br /&gt;
 InstallationConfig_Array_Power Gibt die Nennleistung des Arrays aus der Anzahl der einzelnen Batterien an. Es wurde eine Leistung von 1.28 KW pro Batterie als Basis angenommen&lt;br /&gt;
==== RAW Definition BYD_Status ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr BYD_Status DbLogExclude .*&lt;br /&gt;
attr BYD_Status devStateIcon 100:measure_battery_100 \d:measure_battery_0 1\d.*:measure_battery_25 2\d.*:measure_battery_25 3\d.*:measure_battery_25 4\d.*:measure_battery_50 5\d.*:measure_battery_50 6\d.*:measure_battery_50 7\d.*:measure_battery_75 8\d.*:measure_battery_75 9\d.*:measure_battery_100&lt;br /&gt;
attr BYD_Status enableControlSet 0&lt;br /&gt;
attr BYD_Status enableCookies 1&lt;br /&gt;
attr BYD_Status get01-101Name Array_Series_Battery_CellVol_02&lt;br /&gt;
attr BYD_Status get01-106Name Array_Series_Battery_CellVol_03&lt;br /&gt;
attr BYD_Status get01-111Name Array_Series_Battery_CellVol_04&lt;br /&gt;
attr BYD_Status get01-116Name Array_Series_Battery_CellVol_05&lt;br /&gt;
attr BYD_Status get01-11Name Array_Main_PackVoltage&lt;br /&gt;
attr BYD_Status get01-121Name Array_Series_Battery_CellVol_06&lt;br /&gt;
attr BYD_Status get01-126Name Array_Series_Battery_CellVol_07&lt;br /&gt;
attr BYD_Status get01-131Name Array_Series_Battery_CellVol_08&lt;br /&gt;
attr BYD_Status get01-136Name Array_Series_Battery_CellVol_09&lt;br /&gt;
attr BYD_Status get01-141Name Array_Series_Battery_CellVol_10&lt;br /&gt;
attr BYD_Status get01-146Name Array_Series_Battery_CellVol_11&lt;br /&gt;
attr BYD_Status get01-151Name Array_Series_Battery_CellVol_12&lt;br /&gt;
attr BYD_Status get01-156Name Array_Series_Battery_CellVol_13&lt;br /&gt;
attr BYD_Status get01-161Name Array_Series_Battery_CellVol_14&lt;br /&gt;
attr BYD_Status get01-166Name Array_Series_Battery_CellVol_15&lt;br /&gt;
attr BYD_Status get01-16Name Array_Main_Current&lt;br /&gt;
attr BYD_Status get01-171Name Array_Series_Battery_CellVol_16&lt;br /&gt;
attr BYD_Status get01-176Name Array_Series_Battery_CellVolMax&lt;br /&gt;
attr BYD_Status get01-181Name Array_Series_Battery_CellVolMin&lt;br /&gt;
attr BYD_Status get01-186Name Array_Series_Battery_CellTemp_1&lt;br /&gt;
attr BYD_Status get01-191Name Array_Series_Battery_CellTemp_2&lt;br /&gt;
attr BYD_Status get01-196Name Array_Series_Battery_CellTemp_3&lt;br /&gt;
attr BYD_Status get01-201Name Array_Series_Battery_CellTemp_4&lt;br /&gt;
attr BYD_Status get01-22Name Array_Main_SOC&lt;br /&gt;
attr BYD_Status get01-26Name Array_Main_SysTemp&lt;br /&gt;
attr BYD_Status get01-31Name Array_Main_MaxCellVol&lt;br /&gt;
attr BYD_Status get01-36Name Array_Main_MinCellVol&lt;br /&gt;
attr BYD_Status get01-41Name Array_Main_MaxCellTemp&lt;br /&gt;
attr BYD_Status get01-46Name Array_Main_MinCellTemp&lt;br /&gt;
attr BYD_Status get01-53Name Array_Main_MaxVolPos&lt;br /&gt;
attr BYD_Status get01-56Name Array_Series_Battery_SerialNumber&lt;br /&gt;
attr BYD_Status get01-58Name Array_Main_MinVolPos&lt;br /&gt;
attr BYD_Status get01-5Name Array_Main_ArrayNum&lt;br /&gt;
attr BYD_Status get01-63Name Array_Main_MaxTempPos&lt;br /&gt;
attr BYD_Status get01-68Name Array_Main_MinTempPos&lt;br /&gt;
attr BYD_Status get01-6Name Array_Main_ArrayVoltage&lt;br /&gt;
attr BYD_Status get01-73Name Array_Main_Power&lt;br /&gt;
attr BYD_Status get01-80Name Array_Series_Battery&lt;br /&gt;
attr BYD_Status get01-84Name Array_Series_Battery_SerialNumber&lt;br /&gt;
attr BYD_Status get01-86Name Array_Series_Battery_BattVol&lt;br /&gt;
attr BYD_Status get01-91Name Array_Series_Battery_CellVolDiff&lt;br /&gt;
attr BYD_Status get01-96Name Array_Series_Battery_CellVol_01&lt;br /&gt;
attr BYD_Status get01MaxAge 900&lt;br /&gt;
attr BYD_Status get01MaxAgeReplacementMode delete&lt;br /&gt;
attr BYD_Status get01Name RunData&lt;br /&gt;
attr BYD_Status get01RegOpt g&lt;br /&gt;
attr BYD_Status get01Regex value=([+|-]{0,1}\d+.\d+)&amp;gt;|value=(\d+.\d+)%&amp;gt;|value=(\d)&amp;gt;|value=(.*-\d+\s+.*\d)&amp;gt;|selected=&amp;quot;selected&amp;quot;&amp;gt;(\d)&amp;lt;&lt;br /&gt;
attr BYD_Status get01URL http://%IP-Address_BYD%/asp/RunData.asp&lt;br /&gt;
attr BYD_Status get02-101Name Statistic_SpecificInformation_03_StartTime&lt;br /&gt;
attr BYD_Status get02-105Name Statistic_SpecificInformation_03_EndTime&lt;br /&gt;
attr BYD_Status get02-10Name Statistic_SpecificInformation_02_Type&lt;br /&gt;
attr BYD_Status get02-113Name Statistic_SpecificInformation_04_Type&lt;br /&gt;
attr BYD_Status get02-117Name Statistic_SpecificInformation_04_Ah&lt;br /&gt;
attr BYD_Status get02-11Name Statistic_SpecificInformation_02_Ah&lt;br /&gt;
attr BYD_Status get02-121Name Statistic_SpecificInformation_04_KWh&lt;br /&gt;
attr BYD_Status get02-125Name Statistic_SpecificInformation_04_EnvTemp&lt;br /&gt;
attr BYD_Status get02-129Name Statistic_SpecificInformation_04_BatTemp&lt;br /&gt;
attr BYD_Status get02-12Name Statistic_GeneralInformation_Total_Cycle_Counts&lt;br /&gt;
attr BYD_Status get02-133Name Statistic_SpecificInformation_04_StartTime&lt;br /&gt;
attr BYD_Status get02-137Name Statistic_SpecificInformation_04_EndTime&lt;br /&gt;
attr BYD_Status get02-13Name Statistic_SpecificInformation_02_EnvTemp&lt;br /&gt;
attr BYD_Status get02-145Name Statistic_SpecificInformation_05_Type&lt;br /&gt;
attr BYD_Status get02-149Name Statistic_SpecificInformation_05_Ah&lt;br /&gt;
attr BYD_Status get02-14Name Statistic_SpecificInformation_02_BatTemp&lt;br /&gt;
attr BYD_Status get02-153Name Statistic_SpecificInformation_05_KWh&lt;br /&gt;
attr BYD_Status get02-157Name Statistic_SpecificInformation_05_EnvTemp&lt;br /&gt;
attr BYD_Status get02-15Name Statistic_SpecificInformation_02_StartTime&lt;br /&gt;
attr BYD_Status get02-161Name Statistic_SpecificInformation_05_BatTemp&lt;br /&gt;
attr BYD_Status get02-165Name Statistic_SpecificInformation_05_StartTime&lt;br /&gt;
attr BYD_Status get02-169Name Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr BYD_Status get02-16Name Statistic_SpecificInformation_02_EndTime&lt;br /&gt;
attr BYD_Status get02-17Name Statistic_SpecificInformation_01_Type&lt;br /&gt;
attr BYD_Status get02-18Name Statistic_SpecificInformation_03_Type&lt;br /&gt;
attr BYD_Status get02-19Name Statistic_SpecificInformation_03_Ah&lt;br /&gt;
attr BYD_Status get02-20Name Statistic_SpecificInformation_03_KWh&lt;br /&gt;
attr BYD_Status get02-21Name Statistic_SpecificInformation_01_Ah&lt;br /&gt;
attr BYD_Status get02-22Name Statistic_SpecificInformation_03_BatTemp&lt;br /&gt;
attr BYD_Status get02-23Name Statistic_SpecificInformation_03_StartTime&lt;br /&gt;
attr BYD_Status get02-24Name Statistic_SpecificInformation_03_EndTime&lt;br /&gt;
attr BYD_Status get02-25Name Statistic_SpecificInformation_01_KWh&lt;br /&gt;
attr BYD_Status get02-26Name Statistic_SpecificInformation_04_Type&lt;br /&gt;
attr BYD_Status get02-27Name Statistic_SpecificInformation_04_Ah&lt;br /&gt;
attr BYD_Status get02-28Name Statistic_SpecificInformation_04_KWh&lt;br /&gt;
attr BYD_Status get02-29Name Statistic_SpecificInformation_01_EnvTemp&lt;br /&gt;
attr BYD_Status get02-2Name Statistic_GeneralInformation_Total_Charge_Energy&lt;br /&gt;
attr BYD_Status get02-30Name Statistic_SpecificInformation_04_BatTemp&lt;br /&gt;
attr BYD_Status get02-31Name Statistic_SpecificInformation_04_StartTime&lt;br /&gt;
attr BYD_Status get02-32Name Statistic_SpecificInformation_04_EndTime&lt;br /&gt;
attr BYD_Status get02-33Name Statistic_SpecificInformation_01_BatTemp&lt;br /&gt;
attr BYD_Status get02-34Name Statistic_SpecificInformation_05_Type&lt;br /&gt;
attr BYD_Status get02-35Name Statistic_SpecificInformation_05_Ah&lt;br /&gt;
attr BYD_Status get02-36Name Statistic_SpecificInformation_05_KWh&lt;br /&gt;
attr BYD_Status get02-37Name Statistic_SpecificInformation_01_StartTime&lt;br /&gt;
attr BYD_Status get02-38Name Statistic_SpecificInformation_05_BatTemp&lt;br /&gt;
attr BYD_Status get02-39Name Statistic_SpecificInformation_05_StartTime&lt;br /&gt;
attr BYD_Status get02-3Name Statistic_SpecificInformation_01_Ah&lt;br /&gt;
attr BYD_Status get02-40Name Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr BYD_Status get02-41Name Statistic_SpecificInformation_01_EndTime&lt;br /&gt;
attr BYD_Status get02-49Name Statistic_SpecificInformation_02_Type&lt;br /&gt;
attr BYD_Status get02-4Name Statistic_SpecificInformation_01_KWh&lt;br /&gt;
attr BYD_Status get02-53Name Statistic_SpecificInformation_02_Ah&lt;br /&gt;
attr BYD_Status get02-57Name Statistic_SpecificInformation_02_KWh&lt;br /&gt;
attr BYD_Status get02-5Name Statistic_SpecificInformation_01_EnvTemp&lt;br /&gt;
attr BYD_Status get02-61Name Statistic_SpecificInformation_02_EnvTemp&lt;br /&gt;
attr BYD_Status get02-65Name Statistic_SpecificInformation_02_BatTemp&lt;br /&gt;
attr BYD_Status get02-69Name Statistic_SpecificInformation_02_StartTime&lt;br /&gt;
attr BYD_Status get02-6Name Statistic_SpecificInformation_01_BatTemp&lt;br /&gt;
attr BYD_Status get02-73Name Statistic_SpecificInformation_02_EndTime&lt;br /&gt;
attr BYD_Status get02-7Name Statistic_GeneralInformation_Total_Discharge_Energy&lt;br /&gt;
attr BYD_Status get02-81Name Statistic_SpecificInformation_03_Type&lt;br /&gt;
attr BYD_Status get02-85Name Statistic_SpecificInformation_03_Ah&lt;br /&gt;
attr BYD_Status get02-89Name Statistic_SpecificInformation_03_KWh&lt;br /&gt;
attr BYD_Status get02-8Name Statistic_SpecificInformation_01_EndTime&lt;br /&gt;
attr BYD_Status get02-93Name Statistic_SpecificInformation_03_EnvTemp&lt;br /&gt;
attr BYD_Status get02-97Name Statistic_SpecificInformation_03_BatTemp&lt;br /&gt;
attr BYD_Status get02MaxAge 900&lt;br /&gt;
attr BYD_Status get02MaxAgeReplacementMode delete&lt;br /&gt;
attr BYD_Status get02Name StatisticInformation&lt;br /&gt;
attr BYD_Status get02RegOpt g&lt;br /&gt;
attr BYD_Status get02Regex &amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(.*)&amp;lt;\/td&amp;gt;\n|Charge Energy:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+.\d+)|Discharge Energy:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+.\d+)|Cycle Counts:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+)&lt;br /&gt;
attr BYD_Status get02URL http://%IP-Address_BYD%/asp/StatisticInformation.asp&lt;br /&gt;
attr BYD_Status get03-10Name DeviceInformation_Machine_Version&lt;br /&gt;
attr BYD_Status get03-10OExpr {$val =~ s/\n//g;; $val}&lt;br /&gt;
attr BYD_Status get03-15Name DeviceInformation_Board_SN&lt;br /&gt;
attr BYD_Status get03-1Name DeviceInformation_Machine_SN&lt;br /&gt;
attr BYD_Status get03-20Name DeviceInformation_Board_Factory_time&lt;br /&gt;
attr BYD_Status get03-8Name DeviceInformation_Machine_Factory_time&lt;br /&gt;
attr BYD_Status get03Name DeviceInformation&lt;br /&gt;
attr BYD_Status get03RegOpt g&lt;br /&gt;
attr BYD_Status get03Regex &amp;gt;(\d{9}-\d{5})&amp;lt;|Version:&amp;lt;\/td&amp;gt;\n&amp;lt;td&amp;gt;(V\d.\d{3}\n [A-Z])&amp;lt;|&amp;gt;SN:&amp;lt;\/td&amp;gt;\n.*&amp;gt;([\d|\w]{18})&amp;lt;|(\d{4}-\d+-\d+ \d+:\d+:\d+)&lt;br /&gt;
attr BYD_Status get03URL http://%IP-Address_BYD%/asp/DeviceInformation.asp&lt;br /&gt;
attr BYD_Status get04-13Name BatteryInformation_SOC&lt;br /&gt;
attr BYD_Status get04-17Name BatteryInformation_SysTemp&lt;br /&gt;
attr BYD_Status get04-1Name BatteryInformation_TotalVoltage&lt;br /&gt;
attr BYD_Status get04-21Name BatteryInformation_MaxCellVol&lt;br /&gt;
attr BYD_Status get04-25Name BatteryInformation_MinCellVol&lt;br /&gt;
attr BYD_Status get04-29Name BatteryInformation_MaxCellTemp&lt;br /&gt;
attr BYD_Status get04-33Name BatteryInformation_MinCellTemp&lt;br /&gt;
attr BYD_Status get04-37Name BatteryInformation_Power&lt;br /&gt;
attr BYD_Status get04-42Name BatteryInformation_System_state&lt;br /&gt;
attr BYD_Status get04-47Name BatteryInformation_Date_and_Time&lt;br /&gt;
attr BYD_Status get04-52Name BatteryInformation_Alarm_state&lt;br /&gt;
attr BYD_Status get04-5Name BatteryInformation_PackVoltage&lt;br /&gt;
attr BYD_Status get04-9Name BatteryInformation_Current&lt;br /&gt;
attr BYD_Status get04MaxAge 900&lt;br /&gt;
attr BYD_Status get04MaxAgeReplacementMode delete&lt;br /&gt;
attr BYD_Status get04Name BatteryInformation&lt;br /&gt;
attr BYD_Status get04RegOpt g&lt;br /&gt;
attr BYD_Status get04Regex value=([+|-]{0,1}\d+.\d+)[%]{0,1}&amp;gt;|value=([A-Z]+)&amp;gt;|value=&amp;quot;(\d{4}-\d+-\d+ \d+:\d+:\d+)&amp;quot;|Alarm state:&amp;lt;\/h3&amp;gt;&amp;lt;\/td&amp;gt;\n&amp;lt;td&amp;gt;.*&amp;quot;&amp;gt;(\w+\W)&amp;lt;\/font&amp;gt;&lt;br /&gt;
attr BYD_Status get04URL http://%IP-Address_BYD%/asp/Home.asp&lt;br /&gt;
attr BYD_Status get05-1Name InstallationConfig_Array_Counts&lt;br /&gt;
attr BYD_Status get05-5Name InstallationConfig_Series_Battery_Counts&lt;br /&gt;
attr BYD_Status get05-9Name InstallationConfig_Installation_Time&lt;br /&gt;
attr BYD_Status get05Name InstallationConfig&lt;br /&gt;
attr BYD_Status get05RegOpt g&lt;br /&gt;
attr BYD_Status get05Regex &amp;gt;Array Counts :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d){1}&amp;lt;|&amp;gt;Series Battery Counts :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d){1}&amp;lt;|&amp;gt;Installation Time :&amp;lt;\/td&amp;gt;\n&amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(\d{4}-\d+-\d+ \d+:\d+:\d+)&amp;lt;&lt;br /&gt;
attr BYD_Status get05URL http://%IP-Address_BYD%/asp/UserInfo.asp&lt;br /&gt;
attr BYD_Status getHeader01 Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp%&amp;quot;, algorithm=MD5, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=%auth_nc%, cnonce=&amp;quot;%auth_cnonce%&amp;quot;&lt;br /&gt;
attr BYD_Status group PV Eigenverbrauch&lt;br /&gt;
attr BYD_Status httpVersion 1.1&lt;br /&gt;
attr BYD_Status icon measure_battery_100&lt;br /&gt;
attr BYD_Status reAuthRegex Unauthorized&lt;br /&gt;
attr BYD_Status reading01Name auth_qop&lt;br /&gt;
attr BYD_Status reading01Regex qop=&amp;quot;(.*)&amp;quot;, nonce&lt;br /&gt;
attr BYD_Status reading02Name auth_nonce&lt;br /&gt;
attr BYD_Status reading02Regex nonce=&amp;quot;(.*)&amp;quot;, opaque&lt;br /&gt;
attr BYD_Status reading03Name auth_opaque&lt;br /&gt;
attr BYD_Status reading03Regex opaque=&amp;quot;(.*)&amp;quot;,algorithm&lt;br /&gt;
attr BYD_Status reading04Name auth_realm&lt;br /&gt;
attr BYD_Status reading04Regex realm=&amp;quot;(.*)&amp;quot;, domain&lt;br /&gt;
attr BYD_Status replacement01Mode expression&lt;br /&gt;
attr BYD_Status replacement01Regex %IP-Address_BYD%&lt;br /&gt;
attr BYD_Status replacement01Value ReadingsVal(&amp;quot;PV_Anlage_1_config&amp;quot;,&amp;quot;IP-Address_BYD&amp;quot;,&amp;quot;&amp;quot;)&lt;br /&gt;
attr BYD_Status replacement03Mode reading&lt;br /&gt;
attr BYD_Status replacement03Regex %auth_realm%&lt;br /&gt;
attr BYD_Status replacement03Value auth_realm&lt;br /&gt;
attr BYD_Status replacement04Mode reading&lt;br /&gt;
attr BYD_Status replacement04Regex %auth_nonce%&lt;br /&gt;
attr BYD_Status replacement04Value auth_nonce&lt;br /&gt;
attr BYD_Status replacement05Mode reading&lt;br /&gt;
attr BYD_Status replacement05Regex %auth_response%&lt;br /&gt;
attr BYD_Status replacement05Value auth_response&lt;br /&gt;
attr BYD_Status replacement06Mode reading&lt;br /&gt;
attr BYD_Status replacement06Regex %auth_opaque%&lt;br /&gt;
attr BYD_Status replacement06Value auth_opaque&lt;br /&gt;
attr BYD_Status replacement07Mode reading&lt;br /&gt;
attr BYD_Status replacement07Regex %auth_nc%&lt;br /&gt;
attr BYD_Status replacement07Value auth_nc&lt;br /&gt;
attr BYD_Status replacement08Mode reading&lt;br /&gt;
attr BYD_Status replacement08Regex %auth_cnonce%&lt;br /&gt;
attr BYD_Status replacement08Value auth_cnonce&lt;br /&gt;
attr BYD_Status room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr BYD_Status showBody 0&lt;br /&gt;
attr BYD_Status showError 0&lt;br /&gt;
attr BYD_Status sortby 03&lt;br /&gt;
attr BYD_Status stateFormat {round(ReadingsVal(&amp;quot;BYD_Status&amp;quot;,&amp;quot;BatteryInformation_SOC&amp;quot;,0),0)}&lt;br /&gt;
attr BYD_Status userReadings auth_first_called:auth_nonce.* {my $first_called = InternalVal(&amp;quot;$NAME&amp;quot;,&amp;quot;path&amp;quot;,&amp;quot;n.a&amp;quot;);;;; $first_called =~ s/:/_/g;;;; $first_called =~ s/\/api\/v1//g;;;; $first_called},\&lt;br /&gt;
auth_HA1:auth_first_called.* {md5_hex(&amp;quot;installer:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_realm&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;lt;Passwort&amp;gt;&amp;quot;)},\&lt;br /&gt;
auth_HA2:auth_HA1.* {md5_hex(&amp;quot;GET:/asp/RunData.asp&amp;quot;)},\&lt;br /&gt;
auth_response:auth_HA2.* {md5_hex(ReadingsVal($NAME,&amp;quot;auth_HA1&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_nc&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_cnonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_qop&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_HA2&amp;quot;,&amp;quot;&amp;quot;))},\&lt;br /&gt;
auth_nc:auth_nonce.* {&amp;quot;00000001&amp;quot;},\&lt;br /&gt;
auth_cnonce:auth_response.* {&amp;quot;d789ea5b7e9a2377&amp;quot;},\&lt;br /&gt;
auth_Step1_Message:auth_nonce.* {&amp;quot;HTTP nonce updated&amp;quot;},\&lt;br /&gt;
Specific_Information_00_Date:Statistic_SpecificInformation_05_EndTime.* { fhem(&amp;quot;deletereading &amp;quot;.$NAME.&amp;quot; StatisticInformation.*&amp;quot;);;;; localtime()}\&lt;br /&gt;
## auth_Step2_Message:auth_Step1_Message.* { fhem(&amp;quot;get &amp;quot;.$NAME.&amp;quot; RunData&amp;quot;) ;;;; &amp;quot;HTTP Request RunData called&amp;quot; },\&lt;br /&gt;
\&lt;br /&gt;
InstallationConfig_Array_Power:InstallationConfig_Series_Battery_Counts.* {1.28 * ReadingsVal($NAME,&amp;quot;InstallationConfig_Series_Battery_Counts&amp;quot;,0)}&lt;br /&gt;
&lt;br /&gt;
attr BYD_Status verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Timeing für die PV extra Funktionen ==&lt;br /&gt;
=== RAW Definition PV_Schedule (DOIF) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Schedule DOIF ################################################################################################################\&lt;br /&gt;
## 1 BYD Status aktualisieren\&lt;br /&gt;
##\&lt;br /&gt;
 ([+:06] and !([:00] or [:30]))\&lt;br /&gt;
   (\&lt;br /&gt;
      get BYD_Status BatteryInformation\&lt;br /&gt;
   )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Plenticore Status aktualisieren. Dies geschieht über das PV_Anlage_1_API Device\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([:57])\&lt;br /&gt;
   (\&lt;br /&gt;
   get PV_Anlage_1_API 20_/processdata/scb_statistic_EnergyFlow\&lt;br /&gt;
   )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 PV Prognose vom aktuellen Tag aktualisieren\&lt;br /&gt;
##     zwischen 7 und 19 Uhr zur vollen Stunde\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([07:00-20:00] and [:00])\&lt;br /&gt;
   (\&lt;br /&gt;
    {Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_delete_PV_Forecast&amp;quot;,&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)}\&lt;br /&gt;
   )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 PV Prognose für den nächsten Tag aktualisieren\&lt;br /&gt;
## \&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([06:55] or [19:11])\&lt;br /&gt;
   (\&lt;br /&gt;
    {Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_delete_PV_Forecast&amp;quot;,&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)}\&lt;br /&gt;
   )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 regelmäßig die Bilanz aktualisieren\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([+:05] and ![:00]) ## alle 5 Minuten außer um :00\&lt;br /&gt;
  (\&lt;br /&gt;
   get PV_Anlage_1_API 04_/auth/me\&lt;br /&gt;
  )&lt;br /&gt;
attr PV_Schedule DbLogExclude .*&lt;br /&gt;
attr PV_Schedule alias PV_Schedule&lt;br /&gt;
attr PV_Schedule cmdState BYD Status|Plenticore Status&lt;br /&gt;
attr PV_Schedule comment Version 2020.10.23 17:00&lt;br /&gt;
attr PV_Schedule do always&lt;br /&gt;
attr PV_Schedule room Strom-&amp;gt;Photovoltaik,Strom-&amp;gt;System&lt;br /&gt;
attr PV_Schedule sortby 11&lt;br /&gt;
attr PV_Schedule verbose 3&lt;br /&gt;
attr PV_Schedule wait 0:0:0:0:0&lt;br /&gt;
attr PV_Schedule webCmd cmd_1:cmd_2:cmd_3:cmd_4:cmd_5&lt;br /&gt;
attr PV_Schedule webCmdLabel BYD_Status :Statistic_Update :Forecast_0 :Forecast_1 :Bilanz_Actual :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Energie Bilanz ==&lt;br /&gt;
[[Bild:Plenticore Bilanz.png|mini|900px|rechts|]]&lt;br /&gt;
&amp;lt;big&amp;gt;Achtung, es gab eine Umstellung mit diesem Device! Die Bilanz wird nun direkt im PV_Anlage_1_API Device als stateFormat angezeigt. Bitte holt diese Änderung mit den Informationen im Forum Thread nach.&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions und Verbrauchswerte Liefern. Hierbei werden die Momentanwerte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt.&lt;br /&gt;
=== Erstellen von zusätzlichen Werten in der Datenbank ===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|900px|rechts|Die Definition diese Diagramms ist weiter unten beschrieben.]]&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week ====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week device PV_Anlage_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffAccept 7000&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week reading Statistic_EnergyHomePvSum_Year&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week readingNameMap Statistic_EnergyHomePvSum_Week&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month ====&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats.&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert ist der gesamte Verbrauch aus der PV Anlage inklusive Batterie im Monat.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten des Monats\&lt;br /&gt;
Benötigt für SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month device PV_Anlage_1_API&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month reading Statistic_EnergyHomePvSum_Month&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition LogDBRep_Statistic_Yield_Year_diff_Week ====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Year_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage pro Woche an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Benötigt für  SVG_LogDB_PV_Bilanz.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week device PV_Anlage_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week reading Statistic_Yield_Year&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week readingNameMap Statistic_Yield_Week&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Year_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition LogDBRep_Statistic_Yield_Month_max_Month ====&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_Statistic_Yield_Month_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month comment Version 2020.10.23 15:00\&lt;br /&gt;
Dieser Wert gibt den gesamten Ertrag der PV Anlage im Monat an.\&lt;br /&gt;
Gestartet über DB_Service_Schedule am ersten Tag der Folgewoche.\&lt;br /&gt;
Momentan noch in keinem SVC verwendet.&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month device PV_Anlage_1_API&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month diffAccept 20000&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month reading Statistic_Yield_Month&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_begin current_year_begin&lt;br /&gt;
attr LogDBRep_Statistic_Yield_Month_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Timing für die Datenbank Einträge ===&lt;br /&gt;
Über dieses Scheduling werden in der Datenbank zusätzliche Wochen- und Monatseinträge gesteuert.&lt;br /&gt;
==== RAW Definition DB_Service_Schedule ====&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DB_Service_Schedule DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_max_Month maxValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Month_max_Month maxValue writeToDB)\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))\&lt;br /&gt;
 (set LogDBRep_Statistic_EnergyHomePvSum_Year_diff_Week diffValue writeToDB)\&lt;br /&gt;
 (set LogDBRep_Statistic_Yield_Year_diff_Week diffValue writeToDB)&lt;br /&gt;
attr DB_Service_Schedule DbLogExclude .*&lt;br /&gt;
attr DB_Service_Schedule comment Version 2020.10.23 17:00\&lt;br /&gt;
Hier werden zusätzlich Werte in der Datenbank erzeugt.&lt;br /&gt;
attr DB_Service_Schedule do always&lt;br /&gt;
attr DB_Service_Schedule room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr DB_Service_Schedule wait 0,3:0,3&lt;br /&gt;
attr DB_Service_Schedule webCmd cmd_1:cmd_2&lt;br /&gt;
attr DB_Service_Schedule webCmdLabel monatlich :wöchentlich :&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Löschen von nicht mehr benötigten Werten in der Datenbank ===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen trend erkennen lassen.&lt;br /&gt;
Wen eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wetter-/Leistungs-Prognose ==&lt;br /&gt;
Dies ist ein Thema, dass nicht wirklich gut zu fassen ist und ist eher etwas für Enthusiasten :-), wer schon mal mit Sonne, Wolken und Regen gerechnet hat versteht was ich meine. Dieser Ansatz ist nicht wissenschaftlicher Art und hat auch keinen Anspruch mathematischer Perfektion. Nach reinem Gefühl und mit aus dem Fenster schauen kommt jedoch ein respektables Ergebnis dabei heraus. Viel Vergnügen und Spaß beim mitbasteln ;-)&lt;br /&gt;
[[Bild:Plenticore_Forecast_Tagesanfang.png|mini|900px|rechts|Wenn der Tag begonnen hat ist die Prognose vom Vortag bereits im Diagramm. Der Wert Calculation in schwarz ist die aktuelle Korrektur.]]&lt;br /&gt;
==== Wetter Forecast Grundlagen ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1.) Astro Device mit dem Namen Astro und der Konfiguration&lt;br /&gt;
    für den jeweiligen Standort&lt;br /&gt;
2.) DbLog Device, um die Daten in die Datenbank zu schreiben&lt;br /&gt;
3.) DbRep Device um auch wieder alte Forecasts zu löschen&lt;br /&gt;
4.) Das Wetter Device für wunderground wird nicht für den&lt;br /&gt;
    Forecast benötigt.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deutscher Wetter Dienst (DWD) ===&lt;br /&gt;
Der DWD liefert über Mosmix kostenlos, stunden aktuelle Prognosedaten woraus für diese Anwendung die Werte Rad1h und TTT bezogen werden. In der Funktion Solar_forecast erfolgt noch eine Verschiebung um eine Stunde und die Umrechnung von Rad1h in Watt/m² .&lt;br /&gt;
&#039;&#039;&#039;Achtung: nicht alle Stationen liefern auch die Rad1h Daten, was deshalb bitte anhand der readings kontrolliert werden müsste.&#039;&#039;&#039;&lt;br /&gt;
[[DWD_OpenData|FHEM DWD_OpenData Modul]]&lt;br /&gt;
==== RAW Definition DWD_Forecast ====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DWD_Forecast DWD_OpenData&lt;br /&gt;
attr DWD_Forecast DbLogExclude .*&lt;br /&gt;
attr DWD_Forecast forecastDays 1&lt;br /&gt;
attr DWD_Forecast forecastProperties Rad1h,TTT,Neff,R600&lt;br /&gt;
attr DWD_Forecast forecastResolution 1&lt;br /&gt;
attr DWD_Forecast forecastStation P0178&lt;br /&gt;
attr DWD_Forecast group PV Eigenverbrauch&lt;br /&gt;
attr DWD_Forecast icon weather_rain_fog&lt;br /&gt;
attr DWD_Forecast room Informationen-&amp;gt;Wetter,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr DWD_Forecast sortby 06&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 99_myUtils.pm Funktionen ===&lt;br /&gt;
==== Solar_forecast ====&lt;br /&gt;
Achtung, diese Funktion ist noch nicht vollständig ausprogrammiert. Es wurden bereits Übergabeparameter integriert, um z.B. andere Wetterdienste zu berücksichtigen.&lt;br /&gt;
Um diese Funktion zu nutzen muss ein Dummy PV_Anlage_1_config vorhanden sein, in dem unter anderem die Modul und Anlagen Ausrichtung konfiguriert wird.&lt;br /&gt;
Rückfragen gerne im Forum.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
###########################################################&lt;br /&gt;
# Subroutine to calculate radiation&lt;br /&gt;
###########################################################&lt;br /&gt;
sub Solar_forecast($$$$$$) {&lt;br /&gt;
 #&lt;br /&gt;
 # 2020.10.15 15:37&lt;br /&gt;
 #&lt;br /&gt;
 #    Mit &amp;quot;attr global verbose 3&amp;quot; erscheinen Logmeldungen&lt;br /&gt;
 #&lt;br /&gt;
     my $logdb       = $_[0] ;&lt;br /&gt;
     my $logdbrep    = $_[1] ;        # Das wird zum Löschen in der LogDB verwendet und muss entsprechend konfiguriert sein.&lt;br /&gt;
     my $logdevice   = $_[2] ;&lt;br /&gt;
     # Hier könnte man noch andere Wetterdienste berücksichtigen bzw den Device Namen ändern&lt;br /&gt;
     my $wetter      = $_[4] ; if ($wetter ne &amp;quot;DWD_Forecast&amp;quot;) {return(&amp;quot;$wetter not supported&amp;quot;)} ;&lt;br /&gt;
     my $fc          = $_[5] ;        # Wieviel Tage in die Zukunft soll es gehen? 0,1,2&lt;br /&gt;
     my $reading     = $_[3].$fc ;&lt;br /&gt;
&lt;br /&gt;
     my $timeshift = 1;               # Verschiebt die Prognose um eine Stunde&lt;br /&gt;
     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $year += 1900; $mon += 1;&lt;br /&gt;
     my ($Solar_Cloud,$Solar_Rain,$Solar_Temp,$Solar_SolarRadiation,$logentry,$i) = (0) x 6 ;&lt;br /&gt;
     my ($cloudk,$raink,$tempk,$cloudk_base,$raink_base,$tempk_base) = (0) x 6 ;&lt;br /&gt;
     my ($Solar_Correction_Cloud,$Solar_Correction_Rain,$Solar_Correction_Temp,$Solar_Plain) = (1) x 4 ;&lt;br /&gt;
     my (@Solar_,@module_count) = (0,0,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Initialisieren des Basis TIMESTAMP für den Forecast&lt;br /&gt;
     my $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; 07:00:00&amp;quot;) ;&lt;br /&gt;
     my $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
     # Bei Forecast zuerst die bisherigen Einträge in der Datenbank für den Tag löschen&lt;br /&gt;
     fhem &amp;quot;set &amp;quot;.$logdbrep.&amp;quot; sqlCmd DELETE FROM history WHERE DEVICE=&#039;&amp;quot;.$logdevice.&amp;quot;&#039; AND READING=&#039;&amp;quot;.$reading.&amp;quot;&#039; AND TIMESTAMP&amp;gt;=&#039;&amp;quot;.$timestamp.&amp;quot;&#039;&amp;quot; ;&lt;br /&gt;
&lt;br /&gt;
      # Es werden Stundenwerte von 07:00 bis 19:00 Uhr berechnet&lt;br /&gt;
      for ($i = 7; $i &amp;lt;= 19; $i++) {&lt;br /&gt;
        $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; &amp;quot;.$i.&amp;quot;:00:00&amp;quot;) ;&lt;br /&gt;
        $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
        if ( $wetter eq &amp;quot;DWD_Forecast&amp;quot;) {&lt;br /&gt;
          $Solar_Cloud          = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Neff&amp;quot; ,0);&lt;br /&gt;
          $Solar_Rain           = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_R600&amp;quot; ,0);&lt;br /&gt;
          $Solar_Temp           = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_TTT&amp;quot;  ,0)+10;&lt;br /&gt;
          $Solar_SolarRadiation = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Rad1h&amp;quot;,0);&lt;br /&gt;
          $Solar_SolarRadiation = round($Solar_SolarRadiation * 0.277778 ,0);&lt;br /&gt;
          Log 3, &amp;quot;Solar_SolarRadiation   :  &amp;quot;.$Solar_SolarRadiation.&amp;quot; &amp;quot;.ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Rad1h&amp;quot;,0) ;&lt;br /&gt;
         };&lt;br /&gt;
&lt;br /&gt;
        $cloudk = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
        if ($cloudk ne 0) {&lt;br /&gt;
          $cloudk_base = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk_base&amp;quot;,0) ;&lt;br /&gt;
          $Solar_Correction_Cloud = round((1 + ($Solar_Cloud - $cloudk_base) * $cloudk / 100),3) ;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        $raink  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink&amp;quot;,0) * -0.01 ;&lt;br /&gt;
        if ($raink ne 0) {&lt;br /&gt;
          $raink_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink_base&amp;quot; ,0) ;&lt;br /&gt;
          $Solar_Correction_Rain = round((1 + ($Solar_Rain  - $raink_base ) * $raink  / 100),3) ;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        $tempk  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
        if ($tempk ne 0) {&lt;br /&gt;
          $tempk_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk_base&amp;quot; ,0) ;&lt;br /&gt;
          $Solar_Correction_Temp = round((1 + ($Solar_Temp  - $tempk_base ) * $tempk  / 100),3) ;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        my $Solar_Correction_Faktor = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_factor&amp;quot;,1) ;&lt;br /&gt;
&lt;br /&gt;
        $logentry = 0 ;&lt;br /&gt;
        for(my $j=1;$j&amp;lt;4;$j++){&lt;br /&gt;
          $module_count[$j] = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_count&amp;quot;,0) ;&lt;br /&gt;
          if ($module_count[$j] ne 0) {&lt;br /&gt;
            $Solar_Plain = round(Solar_plain(ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0) , ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0) , $timestamp),3) ;&lt;br /&gt;
            Log 3, &amp;quot;plain/direction        :  &amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0).&amp;quot;/&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0).&amp;quot; &amp;gt;&amp;gt;&amp;gt; &amp;quot;.$Solar_Plain ;&lt;br /&gt;
&lt;br /&gt;
            $Solar_[$j]  = $module_count[$j] * ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_power&amp;quot;,1)/1000 ;&lt;br /&gt;
            $Solar_[$j]  = $Solar_[$j] * $Solar_Plain ;&lt;br /&gt;
            $Solar_[$j]  = $Solar_[$j] * $Solar_SolarRadiation ;&lt;br /&gt;
            $Solar_[$j]  = $Solar_[$j] * $Solar_Correction_Temp * $Solar_Correction_Cloud * $Solar_Correction_Rain * $Solar_Correction_Faktor ;&lt;br /&gt;
            $Solar_[$j]  = ($Solar_[$j] lt 0)?0:round($Solar_[$j],0) ;&lt;br /&gt;
&lt;br /&gt;
            $logentry = $logentry + $Solar_[$j] ;&lt;br /&gt;
            if ($fc == 0 and $hour == $i) {&lt;br /&gt;
              Log 3, &amp;quot;Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_name&amp;quot;,0).&amp;quot;            :  &amp;quot;.$Solar_[$j].&amp;quot; &amp;quot;.$i.&amp;quot; Uhr&amp;quot; ;&lt;br /&gt;
              fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_name&amp;quot;,0).&amp;quot; &amp;quot;.$Solar_[$j] ;&lt;br /&gt;
            };&lt;br /&gt;
          };&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        fhem &amp;quot;set &amp;quot;.$logdb.&amp;quot; addCacheLine &amp;quot;.$timestamp.&amp;quot;|&amp;quot;.$logdevice.&amp;quot;|addlog|&amp;quot;.$reading.&amp;quot;: &amp;quot;.$logentry.&amp;quot;|&amp;quot;.$reading.&amp;quot;|&amp;quot;.$logentry.&amp;quot;|&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if ($fc == 0 and $hour == $i and ($module_count[1] ne 0 or $module_count[2] ne 0 or $module_count[3] ne 0)) {&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_SolarRadiation &amp;quot;.$Solar_SolarRadiation ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Cloud &amp;quot;.$Solar_Cloud ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Rain &amp;quot;.$Solar_Rain ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Temp &amp;quot;.$Solar_Temp ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Correction_Cloud &amp;quot;.$Solar_Correction_Cloud ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Correction_Rain &amp;quot;.$Solar_Correction_Rain ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Correction_Temp &amp;quot;.$Solar_Correction_Temp ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Calculation &amp;quot;.$logentry ;&lt;br /&gt;
        } ;&lt;br /&gt;
&lt;br /&gt;
        Log 3, &amp;quot;Solar_Plain            : &amp;quot;.$Solar_Plain ;&lt;br /&gt;
        Log 3, &amp;quot;Solar_SolarRadiation   : &amp;quot;.$Solar_SolarRadiation ;&lt;br /&gt;
        Log 3, &amp;quot;Solar_Cloud            : &amp;quot;.$Solar_Cloud ;&lt;br /&gt;
        Log 3, &amp;quot;cloudk                 : &amp;quot;.$cloudk.&amp;quot; &amp;quot;.$cloudk_base ;&lt;br /&gt;
        Log 3, &amp;quot;Solar_Correction_Cloud : &amp;quot;.$Solar_Correction_Cloud ;&lt;br /&gt;
        Log 3, &amp;quot;Solar_Rain             : &amp;quot;.$Solar_Rain ;&lt;br /&gt;
        Log 3, &amp;quot;raink                  : &amp;quot;.$raink.&amp;quot; &amp;quot;.$raink_base ;&lt;br /&gt;
        Log 3, &amp;quot;Solar_Correction_Rain  : &amp;quot;.$Solar_Correction_Rain ;&lt;br /&gt;
        Log 3, &amp;quot;Solar_Temp             : &amp;quot;.$Solar_Temp ;&lt;br /&gt;
        Log 3, &amp;quot;tempk                  : &amp;quot;.$tempk.&amp;quot; &amp;quot;.$tempk_base ;&lt;br /&gt;
        Log 3, &amp;quot;Solar_Correction_Temp  : &amp;quot;.$Solar_Correction_Temp ;&lt;br /&gt;
        Log 3, $fc.&amp;quot; &amp;quot;.$i.&amp;quot; &amp;quot;.$Solar_SolarRadiation.&amp;quot; &amp;quot;.$logentry ;&lt;br /&gt;
      } ;&lt;br /&gt;
    return (0);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Solar_Plain ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub Solar_plain($$$) {&lt;br /&gt;
 #&lt;br /&gt;
 # 2020.10.15 15:37&lt;br /&gt;
 #&lt;br /&gt;
    my $rad         = 57.296;&lt;br /&gt;
    my $factor      = 0.001;&lt;br /&gt;
&lt;br /&gt;
    # read parameter&lt;br /&gt;
    my $angle       = $_[0];&lt;br /&gt;
    my $orienta     = $_[1];&lt;br /&gt;
    my $time        = $_[2];&lt;br /&gt;
&lt;br /&gt;
    # get Astro information&lt;br /&gt;
    my $azimuth     = fhem &amp;quot;get Astro text SunAz &amp;quot;.$time ;&lt;br /&gt;
    my $elevation   = fhem &amp;quot;get Astro text SunAlt &amp;quot;.$time ;&lt;br /&gt;
&lt;br /&gt;
    # convert in radiant&lt;br /&gt;
    $elevation      = $elevation / $rad;&lt;br /&gt;
    $angle          = $angle     / $rad;&lt;br /&gt;
    my $orientation = ($azimuth - 180 - $orienta) / $rad;&lt;br /&gt;
&lt;br /&gt;
    if(cos($orientation) &amp;lt; 0.05 &amp;amp;&amp;amp; cos($orientation) &amp;gt; -0.2) {&lt;br /&gt;
      $orientation = $orientation - 0.2&lt;br /&gt;
    };&lt;br /&gt;
    Log 3, &amp;quot;Solar_plain: azimuth = $azimuth, orientation=$orientation, elevation=$elevation, angle=$angle&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    # avoid unrealistic values (normally formula should only be used within boundaries of orientation +/- 90 degrees)&lt;br /&gt;
    if ($elevation &amp;lt;= 0.14) {&lt;br /&gt;
      Log 3, &amp;quot;Solar_plain: factor = $factor&amp;quot;;&lt;br /&gt;
      return($factor);&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    $factor = sin($angle) /&lt;br /&gt;
             (sin( $elevation) / cos( $elevation)) *&lt;br /&gt;
              cos($orientation) +&lt;br /&gt;
              cos($angle);&lt;br /&gt;
&lt;br /&gt;
    # avoid too big values&lt;br /&gt;
    if ($factor &amp;gt; - 0.05 &amp;amp;&amp;amp; $factor &amp;lt; 0.05) {&lt;br /&gt;
      $factor = 0.05&lt;br /&gt;
    };&lt;br /&gt;
    Log 3, &amp;quot;Solar_plain: factor = $factor&amp;quot;;&lt;br /&gt;
    return ($factor);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Astro Device ===&lt;br /&gt;
==== RAW Definition Astro ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Astro Astro&lt;br /&gt;
attr Astro DbLogExclude .*&lt;br /&gt;
attr Astro DbLogInclude SunAlt,SunAz&lt;br /&gt;
attr Astro alias Astro&lt;br /&gt;
attr Astro event-on-change-reading SunAlt,SunAz,ObsSeason,ObsSeasonN,.*Twilight.*&lt;br /&gt;
attr Astro group ASC Environment&lt;br /&gt;
attr Astro icon telescope&lt;br /&gt;
attr Astro interval 600&lt;br /&gt;
attr Astro recomputeAt NewDay,SunRise,SunSet,AstroTwilightEvening,AstroTwilightMorning,CivilTwilightEvening,CivilTwilightMorning,CustomTwilightEvening,CustomTwilightMorning&lt;br /&gt;
attr Astro room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr Astro sortby 08&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== fhem.cfg Einträge für das Astro Device ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
attr global altitude 110&lt;br /&gt;
attr global latitude 47.85750&lt;br /&gt;
attr global longitude 9.49420&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== DbLog Device ===&lt;br /&gt;
==== RAW Definition LogDB ====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDB DbLog ./db.conf .*:.*&lt;br /&gt;
attr LogDB DbLogExclude .*&lt;br /&gt;
attr LogDB DbLogSelectionMode Exclude/Include&lt;br /&gt;
attr LogDB DbLogType History&lt;br /&gt;
attr LogDB asyncMode 1&lt;br /&gt;
attr LogDB bulkInsert 1&lt;br /&gt;
attr LogDB disable 0&lt;br /&gt;
attr LogDB room System&lt;br /&gt;
attr LogDB showproctime 1&lt;br /&gt;
attr LogDB verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition LogDBRep_delete_PV_Forecast ====&lt;br /&gt;
Achtung, bitte hier beachten, ob bereits eine andere DbLog verwendet wird.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_delete_PV_Forecast DbRep LogDB&lt;br /&gt;
attr LogDBRep_delete_PV_Forecast DbLogExclude .*&lt;br /&gt;
attr LogDBRep_delete_PV_Forecast allowDeletion 1&lt;br /&gt;
attr LogDBRep_delete_PV_Forecast room System&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Solar Forcast Tests ====&lt;br /&gt;
Grundlagen hierfür sind:&lt;br /&gt;
1.) Astro Device mit dem Namen Astro und der Konfiguration für den Standort (in der fhem.cfg eingetragen)&lt;br /&gt;
2.) DbLog Device, um die Daten in die Datenbank zu schreiben&lt;br /&gt;
3.) DbRep Device um auch wieder alte Forecasts zu löschen&lt;br /&gt;
4.) Die Solar_ Funktionen in der 99_myUtils&lt;br /&gt;
5.) Das Wetter Device für wunderground wird nicht für den Forecast benötigt&lt;br /&gt;
&lt;br /&gt;
===== Astro Device Test =====&lt;br /&gt;
Bei diesen test wird der jeweilige Winkel des Sonnenstandes zu der gegebene Zeit und der eigenen Standortposition zurückgegeben.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
get Astro text SunAz  &amp;quot;2020-10-10 15:00:00&amp;quot;&lt;br /&gt;
get Astro text SunAlt &amp;quot;2020-10-10 15:00:00&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Solar_plain() Test =====&lt;br /&gt;
Diese Funktion kann man folgender Maßen testen.&lt;br /&gt;
&lt;br /&gt;
In der fhem comandline:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_plain(45,20,&amp;quot;2020-10-10 15:00:00&amp;quot;)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei ist 45 die Dachneigung und 20 die Ausrichtung das Dach hätte dem nach also Süd/West Lage&lt;br /&gt;
Datum mit Uhrzeit reicht dann stundenweise hochzuzählen.&lt;br /&gt;
&lt;br /&gt;
Im Log kommt dann folgendes&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
2020.10.10 14:40:05.038 3: get Astro text SunAz 2020-10-10 15:00:00 : 210.6&lt;br /&gt;
2020.10.10 14:40:05.046 3: get Astro text SunAlt 2020-10-10 15:00:00 : 28.6&lt;br /&gt;
2020.10.10 14:40:05.046 3: Solar_plain: azimuth = 210.6, orientation=0.185004188774085, elevation=0.49916224518291, angle=0.785395141022061&lt;br /&gt;
2020.10.10 14:40:05.046 3: Factor: 1.98190505984713&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald der Faktor unsinnig würde, wird von der Funktion 0.001 zurück geliefert. Somit würde die Prognose auf fast null reduziert!&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2020-10-11 15:00:00&amp;quot;) } =&amp;gt; 2.00234055111251&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2020-10-11 16:00:00&amp;quot;) } =&amp;gt; 2.42298713810404&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2020-10-11 17:00:00&amp;quot;) } =&amp;gt; 3.20079343955795&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2020-10-11 18:00:00&amp;quot;) } =&amp;gt; 0.001&lt;br /&gt;
{Solar_plain(45,40,&amp;quot;2020-10-11 19:00:00&amp;quot;) } =&amp;gt; 0.001&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Solar_forecast() Test =====&lt;br /&gt;
Ein erster Test für diese Funktion wäre ein manueller Aufruf in der Kommandozeile. Hierbei ist 0 der aktuelle und 1 der nächste Tag.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
{Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_delete_PV_Forecast&amp;quot;,&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)}&lt;br /&gt;
{Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_delete_PV_Forecast&amp;quot;,&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Forecast Basiseinstellung ===&lt;br /&gt;
Erste Werte wurden bereits mit dem Gerät PV_Anlage_1_config von einer Ost/Süd/West Anlage mitgeliefert.&lt;br /&gt;
&lt;br /&gt;
Grundlegend muss man als erstes jede Ausrichtung von Modulen definieren.&lt;br /&gt;
Steht *_count auf 0 so wird diese Ausrichtung nicht verwendet. Die Nennleistung ergibt sich aus der Anzahl der Module und der Nennleistung pro Modul.&lt;br /&gt;
Der Name ist frei wählbar und könnte auf &amp;quot;Garage&amp;quot; oder &amp;quot;Schuppen&amp;quot; lauten.&lt;br /&gt;
Die Nennleistung pro Modul wird mit dem reading *_power eingetragen.&lt;br /&gt;
Mit *.plain wird der Winkel der Module, bzw die Dachneigung eingetragen.&lt;br /&gt;
Das reading *_direction gibt die Orientierung an, wobei -90 exact Ost, 0 Richtung Süden und +90 Richtung Westen bedeutet. Diese Winkel können sehr gut auf der WEB Seite [https://www.sonnenverlauf.de/#/50.1121,8.6834,18/2020.09.06/15:41/1/3 Sonnenverlauf.de] ermittelt werden. Dort kann man bis auf sein Anlage hereinzoomen und die Orientierung entnehmen.&lt;br /&gt;
&lt;br /&gt;
Sind diese Werte für alle Modulgruppen eingetragen, so wird eine Summe der Einzelleistungen ermittelt und im Gerät PV_Anlage_1 als reading &amp;quot;Solar_Calculation&amp;quot; eingetragen.&lt;br /&gt;
Die weiteren readings &amp;quot;Solar_*&amp;quot; geben noch weitere Werte an.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
module_1_count 13&lt;br /&gt;
module_1_direction -90&lt;br /&gt;
module_1_name East&lt;br /&gt;
module_1_plain 40&lt;br /&gt;
module_1_power 310&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Berücksichtigung von Temperatur, Bewölkung und Regen ===&lt;br /&gt;
Diese Wetterfaktoren haben einen starken Einfluss auf die Leistung, die durch die Module erzeugt wird. Ab hier wird es etwa wie Glaskugellesen, jedoch ist das ergebnis wirklich sehenswert, wenn man sich die Mühe gemacht hat etwas zu experimentieren.&lt;br /&gt;
Für alle Faktoren wurde eine Art Heizungskurve verwendet, da keine lineare Abhängigkeit zu erkennen war. Die Implementierung erhebt keinen Wissenschaftlichen Anspruch!&lt;br /&gt;
&lt;br /&gt;
===== Temperatur =====&lt;br /&gt;
Je heißer die Module werden, je schlechter wird die Leistungsausbeute. Hierzu findet man in den Modulunterlagen einen Wert, der dies wiederspiegelt.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
tempk          dies ist der Faktor aus den Unterlagen ( bei meinen Modulen 0.39 ) und wird dann mit 39 eingetragen&lt;br /&gt;
tempk_base     Dieser Wert hebt die &amp;quot;Heizungskurve&amp;quot; an und wird mit 25 angegeben. Das bedeutet, bei einer Temperatur von 25° wird die Nennleistung erreicht.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Wolken und Regen =====&lt;br /&gt;
Aus den DWD Forecast werden Prozent Werte geliefert, die experimentell in der &amp;quot;Heizungskurve&amp;quot; zu einem Faktor berechnet werden, der dann die zu erwartende Leistung reduziert.&lt;br /&gt;
Um das möglichst gut hinzubekommen sollte man zuerst nur einen Wert verwenden, was man durch raink oder cloudk auf 0 setzen erreichen kann. Eventuell passen ja auch die bereits&lt;br /&gt;
mitgelieferten Werte. Sollte das nicht passen, muss man sich leider doch etwas mit &amp;quot;Heizungskurven&amp;quot; beschäftigen. Es kann die Steilheit der Kurve (cloudk) beeinflusst werden,&lt;br /&gt;
oder auch eine Parallelverschiebung (cloudk_base) stattfinden. Wenn die Wolken einen starken einfluss haben sollen wäre cloudk z.B. zu verändern.&lt;br /&gt;
&lt;br /&gt;
=== wunderground ===&lt;br /&gt;
Diesen Dienst wird nicht für die Prognose genutzt, jedoch kann man dort private Wetterstationen in seinem näheren Umfeld finden, die die Sonneneinstrahlung und den UV Index messen. Das ist dann als aktueller Wert in den Diagrammen zu sehen und lässt aktuelle Beschattung durch Wolken erkennen. Hier kann man dann auch mehrere Stationen definieren und eventuell mit einem Durchschnitt arbeiten, wenn nicht gerade der Nachbar eine Station hat.&lt;br /&gt;
Für diese Abfrage ist keine Registrierung notwendig und man muss auch nicht selber mir einer Station Daten liefern.&lt;br /&gt;
Aber bitte, die Abfrage nicht in einem zu kurzen Abstand, also mit hoher Frequenz stellen! Hier wird alle 15 Minuten (900 Sekunden) abgefragt.&lt;br /&gt;
=== RAW Definition Wetter_&amp;lt;Wohnort&amp;gt; ===&lt;br /&gt;
Ggf. muss UConv vorher noch aktiviert werden:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
define uconvInit notify global:INITIALIZED {use UConv}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod wetter_&amp;lt;Wohnort&amp;gt; HTTPMOD https://www.wunderground.com/dashboard/pws/&amp;lt;Wohnort_Station&amp;gt; 900&lt;br /&gt;
&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogExclude .*&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogInclude solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; alias wetter_&amp;lt;Wohnort&amp;gt;&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; enableControlSet 1&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; event-on-change-reading solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; group ASC Environment&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; icon weather_sunrise&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Name date&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Regex Summary&amp;lt;.*&amp;gt;([[:alpha:]]{1,9} [\d]{1,2}, [\d]{4})&amp;lt;\/strong&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Name dewpointTemperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;\/span&amp;gt;.*PRECIP RATE&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Name dewpointTemperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;\/span&amp;gt;.*PRECIP RATE&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Name humidity&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Regex HUMIDITY.*&amp;gt;([\d\.]+)&amp;lt;.*WIND&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Name precip1hrmetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Regex PRECIP RATE.*&amp;gt;([\d\.]+)&amp;lt;.*PRECIP TOTAL&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Name preciptodaymetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Regex PRECIP TOTAL.*&amp;gt;([\d\.]+)&amp;lt;.*tile-precipitation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Name pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07OExpr UConv::inhg2hpa($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Name pressure_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Name solarRadiation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Regex SOLAR RADIATION.*CURRENT.*weather__text&amp;quot;&amp;gt;([\d\.]+)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Name solarUV&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Regex CURRENT UV.*&amp;gt;([\d\.]+)&amp;lt;.*UV RISK&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Name temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Name temperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Name windChill&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Name windChill_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Name windDirection&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15OExpr UConv::compasspoint2compasspoint($val,&amp;quot;en&amp;quot;,1,&amp;quot;de&amp;quot;)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Name windDirection_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Name windSpeed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Name windSpeed_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Name windGust&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Name windGust_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; sortby 03&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; stateFormat T: temperature °C | F: humidity % | W: windSpeed km/h | D: pressure hPa | U: solarUV | R: solarRadiation W/m²&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; timeout 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Diagramme ==&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
[[Bild:Plenticore_Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_2 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_2 SVG LogDB:SVG_LogDB_Photovoltaik_2:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_2.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-03-16 10:23:52&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Hauptverbraucher&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB PV_Anlage_1:Total_DC_Power:::$val=abs($val)&lt;br /&gt;
#LogDB PV_Anlage_1:Total_PV_Power_reserve::&lt;br /&gt;
#LogDB StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:::$val=abs($val)&lt;br /&gt;
#LogDB shelly02:Power_0::&lt;br /&gt;
#LogDB shelly03:Power::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC&#039; ls l1 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_PV_reserve&#039; ls l2 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Heizung&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Pool&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Waschmaschine&#039; ls l3 lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== RAW Definition Leistungsbezug ===&lt;br /&gt;
[[Bild:Plenticore_Leistungsbezug.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_3 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_3 SVG LogDB:SVG_LogDB_Photovoltaik_3:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_3.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-07-22 13:51:57&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Leistungsbezug&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
set yrange [0:9500]&lt;br /&gt;
set y2range [0:9500]&lt;br /&gt;
&lt;br /&gt;
#LogDB PV_Anlage_1:Total_DC_Power:::$val=abs($val)&lt;br /&gt;
#LogDB PV_Anlage_1:Home_own_consumption_from_PV::&lt;br /&gt;
#LogDB PV_Anlage_1:Home_own_consumption_from_battery::&lt;br /&gt;
#LogDB PV_Anlage_1:Home_own_consumption_from_grid::&lt;br /&gt;
#LogDB PV_Anlage_1:Actual_battery_charge_usable_Power::&lt;br /&gt;
#LogDB PV_Anlage_1:Total_DC_Power_Max::&lt;br /&gt;
#LogDB PV_Anlage_1:Battery_temperature:::$val=$val*100&lt;br /&gt;
#LogDB Heizung:heatSourceIN:::$val=$val*100&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Power&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;own_PV&#039; ls l2fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_use&#039; ls l0fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Grid_use&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_usable&#039; ls l4 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Max&#039; ls l6 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_Temp_Trend&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Out_Temp_Trend&#039; ls l2 lw 2 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== RAW Definition PV_Bilanz ===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_PV_Bilanz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Bilanz SVG LogDB:SVG_LogDB_PV_Bilanz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz alias SVG_LogDB_PV_Bilanz&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz comment Version 2020.10.21 11:37&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz fixedrange year&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Bilanz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-02 09:55:06&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Bilanz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB PV_Anlage_1_API:max_month_Statistic_EnergyHomePvSum_Month:::$val=$val/1000&lt;br /&gt;
#LogDB PV_Anlage_1_API:diff_week_Statistic_EnergyHomePvSum_Week:::$val=$val/1000&lt;br /&gt;
#LogDB PV_Anlage_1_API:diff_week_Statistic_Yield_Week:::$val=$val/1000&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_EnergyHomePvSum_Month&#039; ls l2fill lw 2 with points,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_EnergyHomePvSum_Week&#039; ls l2fill lw 1 with fsteps,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_Yield_Week&#039; ls l1fill lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== SVG_LogDB_PV_Netz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Netz SVG LogDB:SVG_LogDB_PV_Netz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Netz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Netz alias SVG_LogDB_PV_Netz&lt;br /&gt;
attr SVG_LogDB_PV_Netz comment Version 2020.10.21 13:45&lt;br /&gt;
attr SVG_LogDB_PV_Netz fixedrange month&lt;br /&gt;
attr SVG_LogDB_PV_Netz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Netz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Netz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-10-21 13:43:37&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Netz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB PV_Anlage_1_API:Statistic_EnergyFeedInGrid_Day::&lt;br /&gt;
#LogDB PV_Anlage_1_API:Statistic_EnergyHomeGrid_Day:::$val=$val*-1&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_EnergyFeedInGrid_Day&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Statistic_EnergyHomeGrid_Day&#039; ls l0fill lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RAW Definition Forecast / Calculation ===&lt;br /&gt;
[[Bild:Plenticore_Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_4 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_4 SVG LogDB:SVG_LogDB_Photovoltaik_4:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_4.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-17 08:58:42&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Forecast / Calculation&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set yrange [0:10000]&lt;br /&gt;
set y2range [0:10000]&lt;br /&gt;
&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=($val&amp;gt;0?$val*50+7000:7000)&lt;br /&gt;
#LogDB wetter_wolfskehlen_II:solarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_SolarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=7000&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_Calculation_fc1::&lt;br /&gt;
#LogDB PV_Anlage_1:Power_DC_Sum::&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_Calculation::&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_East::&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_South::&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_West::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Sonnenhöhe&#039; ls l7 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiation&#039; ls l8 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiationPrognose&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;70%&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation_fc1&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Power_DC_Sum&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;East&#039; ls l2 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;South&#039; ls l3 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;West&#039; ls l4 lw 0.5 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe ===&lt;br /&gt;
==== RAW Definition LWP_LuftWärmePumpe (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LWP dummy&lt;br /&gt;
attr LWP DbLogExclude .*&lt;br /&gt;
attr LWP DbLogInclude state&lt;br /&gt;
attr LWP alias LWP_LuftWärmePumpe&lt;br /&gt;
attr LWP group PV Eigenverbrauch&lt;br /&gt;
attr LWP icon sani_earth_source_heat_pump&lt;br /&gt;
attr LWP readingList LWP_Button PowerLevelMinTime PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr LWP room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP setList LWP_Button:uzsuToggle,on,off PowerLevelMinTime:slider,60,30,300 PowerLimitOn:slider,1000,250,4000 PowerLimitOff:slider,1000,250,4000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,900,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr LWP sortby 10&lt;br /&gt;
attr LWP stateFormat state&lt;br /&gt;
attr LWP verbose 0&lt;br /&gt;
attr LWP webCmd LWP_Button&lt;br /&gt;
&lt;br /&gt;
setstate LWP off&lt;br /&gt;
setstate LWP 2020-08-05 17:38:03 LWP_Button off&lt;br /&gt;
setstate LWP 2020-03-02 11:56:45 PowerLevelMinTime 600&lt;br /&gt;
setstate LWP 2020-02-05 14:11:42 PowerLimitOff 2250&lt;br /&gt;
setstate LWP 2020-03-02 11:56:39 PowerLimitOn 3000&lt;br /&gt;
setstate LWP 2019-08-02 10:31:21 RunTimeMin 3600&lt;br /&gt;
setstate LWP 2020-02-05 14:13:01 RunTimePerDay 28800&lt;br /&gt;
setstate LWP 2019-12-29 10:47:55 SetCmdOff set shelly01 off 0&lt;br /&gt;
setstate LWP 2019-07-22 15:35:59 SetCmdOn set shelly01 on 0&lt;br /&gt;
setstate LWP 2019-11-09 12:13:04 TimeEnd 16:00&lt;br /&gt;
setstate LWP 2020-04-02 13:51:54 TimeStart 12:30&lt;br /&gt;
setstate LWP 2020-08-05 17:38:03 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LWP_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
    ([LWP_Counter:pulseTimePerDay] &amp;gt;= [LWP:RunTimePerDay] and\&lt;br /&gt;
     [LWP_Counter:pulseTimeIncrement] &amp;gt;= [LWP:RunTimeMin] and\&lt;br /&gt;
     [LWP:state] ne &amp;quot;off&amp;quot; and [LWP:LWP_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot; LWP_PV cmd_1 PV : LWP off&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 50.0&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
  ( ([PV_Anlage_1:Total_PV_Power_reserve]+[StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung]) &amp;lt; [LWP:PowerLimitOff] and\&lt;br /&gt;
     [LWP_Counter:pulseTimeIncrement] &amp;gt;= [LWP:RunTimeMin] and\&lt;br /&gt;
     [LWP:state] ne &amp;quot;off&amp;quot; and\&lt;br /&gt;
     [LWP:LWP_Button] ne &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot; LWP_PV cmd_2 PV : LWP off&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 50.0&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außerkraft,\&lt;br /&gt;
##   wenn wärend der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [LWP:PowerLimitOff] and\&lt;br /&gt;
     [LWP_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
     [LWP_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
     [LWP:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_3 PV : Stop wait timer LWP&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([Astro:ObsSeason] ne &amp;quot;Sommer&amp;quot; and [Astro:ObsSeason] ne &amp;quot;Frühling&amp;quot; and\&lt;br /&gt;
     [PV_Anlage_1:Total_PV_Power_reserve] &amp;gt;= [LWP:PowerLimitOn] and\&lt;br /&gt;
     [[LWP:TimeStart]-[LWP:TimeEnd]] and\&lt;br /&gt;
     [LWP:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
     [LWP_Counter:pulseTimePerDay] &amp;lt; [LWP:RunTimePerDay] and\&lt;br /&gt;
     [Heizung:hotWaterTemperature] &amp;lt; 60 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_4 : LWP on&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP on&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 60.0&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Signal für den PV-Modus der LWP einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([LWP:LWP_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_5 PV : LWP on for manuel PV-Modus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP on&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 60.0&amp;quot;)}\&lt;br /&gt;
     )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Signal für den PV-Modus der LWP abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([LWP:LWP_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
     [$SELF:cmd_nr] eq &amp;quot;5&amp;quot;  )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_6 PV : LWP off after manuel PV-Modus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 50.0&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Stop wait Timer für das Abschalten, wenn die LWP beim Starten noch anläuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
   ([StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;gt; 300 and\&lt;br /&gt;
    [Heizung:opStateHeatPump1] eq &amp;quot;Wärmepumpe kommt&amp;quot; and\&lt;br /&gt;
    [Heizung:opStateHeatPump3] eq &amp;quot;Pumpenvorlauf&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
     ({Log 3, &amp;quot;LWP_PV cmd_7 : Stop wait timer LWP&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 LWP Ende\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
   ([StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;lt; 300 and\&lt;br /&gt;
    [LWP_Counter:pulseTimeIncrement] &amp;gt;= [LWP:RunTimeMin] and\&lt;br /&gt;
    ([Heizung:opStateHeatPump1] ne &amp;quot;Wärmepumpe läuft&amp;quot; or [Heizung:opStateHeatPump3] eq &amp;quot;Luftabtauen&amp;quot; ) and\&lt;br /&gt;
    ([$SELF:cmd_nr] eq &amp;quot;4&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;10&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_8 : LWP run finished&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 50.0&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading LWP LWP_Button off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 LWP Zwangseinschalten: Sollte das Brauchwasser noch nicht aufgeheizt sein, wird um die Hysterese erhöht.\&lt;br /&gt;
##   Dies kann passieren, wenn am Tag vorher der PV-Modus lief und dann das Wasser noch knapp über dem Mindestwert ist.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
   ([Astro:ObsSeason] ne &amp;quot;Sommer&amp;quot; and [Astro:ObsSeason] ne &amp;quot;Frühling&amp;quot; and\&lt;br /&gt;
    [[LWP:TimeEnd]] and\&lt;br /&gt;
    [Heizung:hotWaterTemperature] &amp;lt; 47 and\&lt;br /&gt;
    ([LWP_Counter:pulseTimePerDay] &amp;lt; [Pool:RunTimePerDay] or\&lt;br /&gt;
     [LWP_Counter:countsPerDay] eq 0) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_9 : LWP on for water heating&amp;quot;}\&lt;br /&gt;
\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget &amp;quot;. (ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperature&amp;quot;,46)+4))}\&lt;br /&gt;
\&lt;br /&gt;
     {Log 3, &amp;quot;LWP_PV cmd_9 : LWP hotWaterTemperatureTarget &amp;quot;.ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperatureTarget&amp;quot;,0)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 10 Hohe Priorität im Winter fuer die LWP\&lt;br /&gt;
##    Einschalten, wenn der Pool läuft, der Speicher geladen ist und noch Überschuss da ist.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([Astro:ObsSeason] eq &amp;quot;Winter&amp;quot; and\&lt;br /&gt;
     [PV_Anlage_1:Total_PV_Power_reserve] &amp;gt;= 2000 and\&lt;br /&gt;
     [shelly02:power_0] &amp;gt; 800 and\&lt;br /&gt;
     [PV_Anlage_1:Act_state_of_charge] &amp;gt; 60 and\&lt;br /&gt;
     [Heizung:hotWaterTemperature] &amp;lt; 60 and \&lt;br /&gt;
     [$SELF:cmd_nr] ne &amp;quot;10&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_10 : LWP Priorität&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP_PV cmd_4&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
&lt;br /&gt;
attr LWP_PV DbLogExclude .*&lt;br /&gt;
attr LWP_PV DbLogInclude state,cmd.*,Device,LWP_Status,wait_timer&lt;br /&gt;
attr LWP_PV alias LWP_PV&lt;br /&gt;
attr LWP_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch aus|Stop wait timer|Eigenverbrauch ein|LWP ein für manuellen PV-Modus|LWP aus nach manuellem PV-Modus|Stop wait timer fuer aus|LWP aus nach PV-Modus|LWP Brauchwasser nachheizen|LWP Priorität&lt;br /&gt;
attr LWP_PV do always&lt;br /&gt;
attr LWP_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_PV icon sani_earth_source_heat_pump&lt;br /&gt;
attr LWP_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_PV sortby 01&lt;br /&gt;
attr LWP_PV stateFormat state : LWP_Status : Brauchwasser e_Heizung_hotWaterTemperature °C&lt;br /&gt;
attr LWP_PV userReadings LWP_Status { ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;state&amp;quot;,&amp;quot;&amp;quot;) }&lt;br /&gt;
attr LWP_PV verbose 5&lt;br /&gt;
attr LWP_PV wait 0:10:0:[LWP:PowerLevelMinTime]:0:0:900:0:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- RAW Definition LWP_Signale (Shelly Modul: shelly1pm)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly01 Shelly 192.168.178.55&lt;br /&gt;
attr shelly01 DbLogExclude .*&lt;br /&gt;
attr shelly01 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly01 alias LWP_Signale&lt;br /&gt;
attr shelly01 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly01 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly01 icon taster_ch_1&lt;br /&gt;
attr shelly01 mode relay&lt;br /&gt;
attr shelly01 model shelly1pm&lt;br /&gt;
attr shelly01 room Shelly,Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly01 sortby 02&lt;br /&gt;
attr shelly01 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;power&amp;quot;,0),\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly01 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly01 webCmd |&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod LWP_Counter HourCounter LWP:on.* LWP:off&lt;br /&gt;
attr LWP_Counter DbLogExclude .*&lt;br /&gt;
attr LWP_Counter alias LWP_Counter&lt;br /&gt;
attr LWP_Counter event-min-interval .*:600&lt;br /&gt;
attr LWP_Counter event-on-change-reading .*&lt;br /&gt;
attr LWP_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_Counter icon time_timer&lt;br /&gt;
attr LWP_Counter interval 5&lt;br /&gt;
attr LWP_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_Counter sortby 03&lt;br /&gt;
attr LWP_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition rg_LWP_Status (readingsGroup Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod rg_LWP_Status readingsGroup &amp;lt;Device&amp;gt;,&amp;lt;Information&amp;gt;,&amp;lt;Wert&amp;gt; LWP:&amp;lt;Status&amp;gt;,state LWP:&amp;lt;PowerLevelMinTime&amp;gt;,PowerLevelMinTime LWP:&amp;lt;PowerLimitOn&amp;gt;,PowerLimitOn LWP:&amp;lt;PowerLimitOff&amp;gt;,PowerLimitOff LWP:&amp;lt;TimeStart&amp;gt;,!TimeStart LWP:&amp;lt;TimeEnd&amp;gt;,!TimeEnd LWP:&amp;lt;RunTimeMin&amp;gt;,RunTimeMin LWP_Counter:&amp;lt;RunTimeMin&amp;gt;,pulseTimeIncrement LWP:&amp;lt;RunTimePerDay&amp;gt;,RunTimePerDay LWP_Counter:&amp;lt;RunTimePerDay&amp;gt;,pulseTimePerDay LWP_PV:&amp;lt;wait&amp;gt;,wait_timer LWP_PV:&amp;lt;TimeStart&amp;gt;,timer_01_c04 LWP_PV:&amp;lt;TimeEnd&amp;gt;,timer_02_c04&lt;br /&gt;
attr rg_LWP_Status DbLogExclude .*&lt;br /&gt;
attr rg_LWP_Status alias Status LuftWärmePumpe Eigenverbrauch&lt;br /&gt;
attr rg_LWP_Status commands {state  =&amp;gt; &#039;state:on,off&#039;,\&lt;br /&gt;
PowerLevelMinTime =&amp;gt; &#039;PowerLevelMinTime:selectnumbers,60,60,600,0,lin&#039;,\&lt;br /&gt;
PowerLimitOn =&amp;gt; &#039;PowerLimitOn:selectnumbers,1000,250,4000,0,lin&#039;,\&lt;br /&gt;
PowerLimitOff =&amp;gt; &#039;PowerLimitOff:selectnumbers,1000,250,4000,0,lin&#039;,\&lt;br /&gt;
RunTimeMin =&amp;gt; &#039;RunTimeMin:selectnumbers,300,300,14400,0,lin&#039;,\&lt;br /&gt;
RunTimePerDay =&amp;gt; &#039;RunTimePerDay:selectnumbers,300,300,28800,0,lin&#039;,\&lt;br /&gt;
TimeStart =&amp;gt; &#039;TimeStart:time&#039;,\&lt;br /&gt;
TimeEnd =&amp;gt; &#039;TimeEnd:time&#039;}&lt;br /&gt;
attr rg_LWP_Status group PV Status&lt;br /&gt;
attr rg_LWP_Status nameStyle style=&amp;quot;color:grey&amp;quot;&lt;br /&gt;
attr rg_LWP_Status room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr rg_LWP_Status sortby 01&lt;br /&gt;
attr rg_LWP_Status style style=&amp;quot;font-size:18px&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool===&lt;br /&gt;
==== RAW Definition Pool_Softube (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool dummy&lt;br /&gt;
attr Pool DbLogExclude .*&lt;br /&gt;
attr Pool DbLogInclude state&lt;br /&gt;
attr Pool alias Pool_Softube&lt;br /&gt;
attr Pool event-on-change-reading .*&lt;br /&gt;
attr Pool group PV Eigenverbrauch&lt;br /&gt;
attr Pool icon scene_swimming&lt;br /&gt;
attr Pool readingList Pool_Button PowerLevelMinTime PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay RunTimePerDaySummer RunTimePerDayWinter SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Pool room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool setList Pool_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,500,100,1500 PowerLimitOff:slider,0,100,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,900,300,64800 RunTimePerDaySummer:slider,900,300,7200 RunTimePerDayWinter:slider,3600,900,64800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Pool sortby 11&lt;br /&gt;
attr Pool stateFormat state&lt;br /&gt;
attr Pool verbose 0&lt;br /&gt;
attr Pool webCmd Pool_Button&lt;br /&gt;
&lt;br /&gt;
setstate Pool off&lt;br /&gt;
setstate Pool 2020-08-28 13:30:10 Pool_Button off&lt;br /&gt;
setstate Pool 2019-12-02 10:31:26 PowerLevelMinTime 600&lt;br /&gt;
setstate Pool 2019-11-13 10:58:18 PowerLimitOff 800&lt;br /&gt;
setstate Pool 2019-11-06 11:49:00 PowerLimitOn 1000&lt;br /&gt;
setstate Pool 2020-08-14 16:26:09 RunTimeMin 1800&lt;br /&gt;
setstate Pool 2020-08-28 06:15:00 RunTimePerDay 3600&lt;br /&gt;
setstate Pool 2020-08-16 13:17:45 RunTimePerDaySummer 3600&lt;br /&gt;
setstate Pool 2020-08-25 19:32:33 RunTimePerDayWinter 14400&lt;br /&gt;
setstate Pool 2019-08-01 14:18:08 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool 2019-08-02 09:33:06 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool 2019-10-31 21:53:28 TimeEnd 16:00&lt;br /&gt;
setstate Pool 2020-04-08 18:19:29 TimeStart 12:30&lt;br /&gt;
setstate Pool 2020-08-28 14:13:02 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
 ([Pool_Counter:pulseTimePerDay] &amp;gt;= [Pool:RunTimePerDay] and\&lt;br /&gt;
  [Pool_Counter:pulseTimeIncrement] &amp;gt;= [Pool:RunTimeMin] and\&lt;br /&gt;
  [Pool:state] eq &amp;quot;on&amp;quot; and [Pool:Pool_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_1 : Pool off&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist.\&lt;br /&gt;
##   Bei Pool Nutzung und Pflegeprogramm wird nicht abgeschaltet.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Pool:PowerLimitOff] and\&lt;br /&gt;
  [Pool_Counter:pulseTimeIncrement] &amp;gt;= [Pool:RunTimeMin] and\&lt;br /&gt;
  [Pool:state] eq &amp;quot;on&amp;quot; and \&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;10&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_2 : Pool off&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Pool Pool_Button off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
##   wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Pool:PowerLimitOff] and\&lt;br /&gt;
  [$SELF:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [$SELF:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Pool:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_3 : Stop wait timer Pool&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch einschalten: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist wird\&lt;br /&gt;
##    und die Laufzeit pro Tag noch nicht erreicht ist;; Bei über 7000 Watt Einspeisung sofort aktivieren\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_Anlage_1:Total_PV_Power_reserve] &amp;gt;= [Pool:PowerLimitOn] and\&lt;br /&gt;
   [[Pool:TimeStart]-[Pool:TimeEnd]] and\&lt;br /&gt;
   [Pool:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
   [Pool_Counter:pulseTimePerDay] &amp;lt; [Pool:RunTimePerDay]\&lt;br /&gt;
  ) or\&lt;br /&gt;
  [PV_Anlage_1:Total_active_power_(powermeter)] &amp;lt;= -7000\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_4 : Pool on&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool on&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose für die Benutzung des Pools einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Pool:Pool_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_5 : Pool on for usage&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool on&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Pools abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Pool:Pool_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_6 : Pool off after usage&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Stop wait Timer für das Abschalten, wenn die Pumpe beim Starten noch anläuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly02:power_0] &amp;gt; 10 and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;9&amp;quot;) and\&lt;br /&gt;
  [$SELF:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [$SELF:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Pool:state] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_7 : Stop wait timer Pool&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly02:power_0] &amp;lt; 10 and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;9&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_8 : Pool run finished&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Pool Pool_Button off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Pool:TimeEnd]] and\&lt;br /&gt;
  ([Pool_Counter:pulseTimePerDay] &amp;lt; [Pool:RunTimePerDay] or\&lt;br /&gt;
   [Pool_Counter:countsPerDay] eq 0)\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_9 : Pool on for maintanance&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool on&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 10 Pflege Zwangseinschaltung bei günstigem Strom nachts im Winter\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Astro:ObsSeason] eq &amp;quot;Winter&amp;quot; and\&lt;br /&gt;
  [Strom_Kosten:aWATTar_Trigger] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [22:00-05:00]\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_10 : Pool on for maintanance by aWATTar&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool on&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 11 Abschaltung bei teurem Strom\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Astro:ObsSeason] eq &amp;quot;Winter&amp;quot; and\&lt;br /&gt;
  [Strom_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;10&amp;quot;\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_11 : Pool off after maintanance by aWATTar&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 12 Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([06:15] and [Heizung:averageAmbientTemperature])\&lt;br /&gt;
\&lt;br /&gt;
    (\&lt;br /&gt;
     { if ( [Heizung:averageAmbientTemperature] &amp;gt;= 18 )\&lt;br /&gt;
         {fhem(&amp;quot;setreading Pool RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;RunTimePerDaySummer&amp;quot;,0) )}\&lt;br /&gt;
      else \&lt;br /&gt;
         {fhem(&amp;quot;setreading Pool RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;RunTimePerDayWinter&amp;quot;,0) )}\&lt;br /&gt;
     },\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV cmd_12 : Pool RunTimePerDay switched&amp;quot;}\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
attr Pool_PV DbLogExclude .*&lt;br /&gt;
attr Pool_PV DbLogInclude cmd.*,state,cmd.*,Device,Pool_Pumpe_Status,wait_timer&lt;br /&gt;
attr Pool_PV alias Pool_PV&lt;br /&gt;
attr Pool_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch aus|Stop wait timer|Eigenverbrauch freigegeben|Pool ein für Benutzung|Pool aus nach Benutzung|Stop wait timer für aus|Pool aus|Pflegemodus ohne PV|Strombörse ein|Strombörse aus|RunTimePerDay switched&lt;br /&gt;
attr Pool_PV disable 0&lt;br /&gt;
attr Pool_PV do always&lt;br /&gt;
attr Pool_PV event-on-change-reading .*&lt;br /&gt;
attr Pool_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV icon scene_swimming&lt;br /&gt;
attr Pool_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV sortby 11&lt;br /&gt;
attr Pool_PV stateFormat state : Pool_Pumpe_Status&lt;br /&gt;
attr Pool_PV userReadings Pool_Pumpe_Status { ReadingsVal(&amp;quot;shelly02&amp;quot;,&amp;quot;power_0&amp;quot;,0)&amp;gt;10 ? &amp;quot;Pool_Pumpe_laeuft&amp;quot; : &amp;quot;Pool_Pumpe_aus&amp;quot;}&lt;br /&gt;
attr Pool_PV verbose 0&lt;br /&gt;
attr Pool_PV wait 0:10:0:[Pool:PowerLevelMinTime]:0:0:0:300:0:300&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool_Signale&lt;br /&gt;
attr shelly02 comment relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 12&lt;br /&gt;
attr shelly02 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly02 userReadings WebLink:network { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_Counter HourCounter shelly02:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly02:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Pool_Counter DbLogExclude .*&lt;br /&gt;
attr Pool_Counter alias Pool_Counter&lt;br /&gt;
attr Pool_Counter comment On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Pool_Counter event-on-change-reading .*&lt;br /&gt;
attr Pool_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_Counter icon time_timer&lt;br /&gt;
attr Pool_Counter interval 5&lt;br /&gt;
attr Pool_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_Counter sortby 13&lt;br /&gt;
attr Pool_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition rg_Pool_Status (readingsGroup Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod rg_Pool_Status readingsGroup &amp;lt;Device&amp;gt;,&amp;lt;Information&amp;gt;,&amp;lt;Wert&amp;gt; Pool:&amp;lt;Status&amp;gt;,!state Pool:&amp;lt;PowerLevelMinTime&amp;gt;,!PowerLevelMinTime Pool:&amp;lt;PowerLimitOn&amp;gt;,!PowerLimitOn Pool:&amp;lt;PowerLimitOff&amp;gt;,!PowerLimitOff Pool:&amp;lt;TimeStart&amp;gt;,!TimeStart Pool:&amp;lt;TimeEnd&amp;gt;,!TimeEnd Pool:&amp;lt;RunTimeMin&amp;gt;,!RunTimeMin Pool_Counter:&amp;lt;RunTimeMin&amp;gt;,!pulseTimeIncrement Pool:&amp;lt;RunTimePerDay&amp;gt;,!RunTimePerDay Pool:&amp;lt;RunTimePerDaySummer&amp;gt;,!RunTimePerDaySummer Pool:&amp;lt;RunTimePerDayWinter&amp;gt;,!RunTimePerDayWinter Pool_Counter:&amp;lt;RunTimePerDay&amp;gt;,!pulseTimePerDay Pool_PV:&amp;lt;wait&amp;gt;,wait_timer Pool_PV:&amp;lt;TimeStart&amp;gt;,timer_01_c04 Pool_PV:&amp;lt;TimeEnd&amp;gt;,timer_02_c04&lt;br /&gt;
attr rg_Pool_Status DbLogExclude .*&lt;br /&gt;
attr rg_Pool_Status alias Status Softube Pool Eigenverbrauch&lt;br /&gt;
attr rg_Pool_Status commands {state  =&amp;gt; &#039;state:on,off&#039;,\&lt;br /&gt;
PowerLevelMinTime =&amp;gt; &#039;PowerLevelMinTime:selectnumbers,60,30,600,0,lin&#039;,\&lt;br /&gt;
PowerLimitOn =&amp;gt; &#039;PowerLimitOn:selectnumbers,500,250,1500,0,lin&#039;,\&lt;br /&gt;
PowerLimitOff =&amp;gt; &#039;PowerLimitOff:selectnumbers,0,100,1000,0,lin&#039;,\&lt;br /&gt;
RunTimeMin =&amp;gt; &#039;RunTimeMin:selectnumbers,300,300,14400,0,lin&#039;,\&lt;br /&gt;
RunTimePerDaySummer =&amp;gt; &#039;RunTimePerDaySummer:selectnumbers,300,300,3600,0,lin&#039;,\&lt;br /&gt;
RunTimePerDayWinter =&amp;gt; &#039;RunTimePerDayWinter:selectnumbers,3600,900,64800,0,lin&#039;,\&lt;br /&gt;
TimeStart =&amp;gt; &#039;TimeStart:time&#039;,\&lt;br /&gt;
TimeEnd =&amp;gt; &#039;TimeEnd:time&#039;}&lt;br /&gt;
attr rg_Pool_Status group PV Status&lt;br /&gt;
attr rg_Pool_Status nameStyle style=&amp;quot;color:grey&amp;quot;&lt;br /&gt;
attr rg_Pool_Status room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr rg_Pool_Status sortby 02&lt;br /&gt;
attr rg_Pool_Status style style=&amp;quot;font-size:18px&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine dummy&lt;br /&gt;
attr Waschmaschine DbLogExclude .*&lt;br /&gt;
attr Waschmaschine DbLogInclude state&lt;br /&gt;
attr Waschmaschine alias Waschmaschine&lt;br /&gt;
attr Waschmaschine group PV Eigenverbrauch&lt;br /&gt;
attr Waschmaschine icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine readingList Waschmaschine_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Waschmaschine room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine setList Waschmaschine_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Waschmaschine sortby 12&lt;br /&gt;
attr Waschmaschine stateFormat state&lt;br /&gt;
attr Waschmaschine verbose 0&lt;br /&gt;
attr Waschmaschine webCmd Waschmaschine_Button&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine off&lt;br /&gt;
setstate Waschmaschine 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine 2019-11-06 10:56:22 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine 2020-04-20 13:06:04 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine 2019-12-02 15:01:18 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine 2020-04-02 13:59:34 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine 2020-01-01 16:29:10 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine 2020-01-01 16:29:24 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine 2019-08-01 14:25:25 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Waschmaschine 2020-08-27 16:17:23 Waschmaschine_Button off&lt;br /&gt;
setstate Waschmaschine 2020-08-28 16:29:42 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [Waschmaschine:RunTimePerDay] and\&lt;br /&gt;
  [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [Waschmaschine:RunTimeMin] and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;on&amp;quot; and [Waschmaschine:Waschmaschine_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Waschprogramm bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
## ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Waschmaschine:PowerLimitOff] and\&lt;br /&gt;
##  [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [Waschmaschine:RunTimeMin] and\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Waschmaschine:PowerLimitOn] and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Waschmaschine:PowerLimitOff] and\&lt;br /&gt;
  [Waschmaschine_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Waschmaschine_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_3 : Waschmaschine stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;gt; [Waschmaschine:PowerLimitOn] and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Waschmaschine:TimeStart]-[Waschmaschine:TimeEnd]] and\&lt;br /&gt;
  [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [Waschmaschine:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_4 : Waschmaschine freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung der Waschmaschine einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Waschmaschine:Waschmaschine_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_5 : Waschmaschine manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose der Waschmaschine manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Waschmaschine:Waschmaschine_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_6 : Waschmaschine manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly03:power] &amp;gt; 0 and\&lt;br /&gt;
  [shelly03:power_Waschmaschine_avg] &amp;lt; 70 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_7 : Waschmaschine Programm gestarted&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Waschprogramm gestartet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose beim Waschprogramm Ende\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly03:power] == 0 and\&lt;br /&gt;
  [shelly03:power_Waschmaschine_avg] &amp;gt; 0 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_8 : Waschmaschine aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine Waschmaschine_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Waschprogramm beendet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn die Waschmaschine nicht gebraucht wurde\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Waschmaschine:PowerLimitOn] and\&lt;br /&gt;
  [[Waschmaschine:TimeEnd]-[Waschmaschine:TimeStart]] and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine Waschmaschine_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Waschmaschine_PV DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV DbLogInclude state,STATE,cmd.*,Device,Waschmaschine_Status,wait_timer&lt;br /&gt;
attr Waschmaschine_PV alias Waschmaschine_PV&lt;br /&gt;
attr Waschmaschine_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Waschmaschine manuell ein|Waschmaschine manuell aus|Waschmaschine laeuft|Waschmaschine aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Waschmaschine_PV do always&lt;br /&gt;
attr Waschmaschine_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV sortby 21&lt;br /&gt;
attr Waschmaschine_PV stateFormat state : Waschmaschine_Status&lt;br /&gt;
attr Waschmaschine_PV verbose 0&lt;br /&gt;
attr Waschmaschine_PV wait 0:0:0:[Waschmaschine:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.54&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine_Signale&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 22&lt;br /&gt;
attr shelly03 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly03 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) },\&lt;br /&gt;
power_Waschmaschine_avg:power.* { movingAverage($NAME,&amp;quot;power&amp;quot;,300) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 23&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition rg_Waschmaschine_Status (readingsGroup Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod rg_Waschmaschine_Status readingsGroup &amp;lt;Device&amp;gt;,&amp;lt;Information&amp;gt;,&amp;lt;Wert&amp;gt; Waschmaschine:&amp;lt;Status&amp;gt;,!state Waschmaschine:&amp;lt;PowerLevelMinTime&amp;gt;,!PowerLevelMinTime Waschmaschine:&amp;lt;PowerLimitOn&amp;gt;,!PowerLimitOn Waschmaschine:&amp;lt;PowerLimitOff&amp;gt;,!PowerLimitOff Waschmaschine:&amp;lt;TimeStart&amp;gt;,!TimeStart Waschmaschine:&amp;lt;TimeEnd&amp;gt;,!TimeEnd Waschmaschine:&amp;lt;RunTimeMin&amp;gt;,!RunTimeMin Waschmaschine_Counter:&amp;lt;RunTimeMin&amp;gt;,!pulseTimeIncrement Waschmaschine:&amp;lt;RunTimePerDay&amp;gt;,!RunTimePerDay Waschmaschine_Counter:&amp;lt;RunTimePerDay&amp;gt;,!pulseTimePerDay Waschmaschine_PV:&amp;lt;wait&amp;gt;,wait_timer Waschmaschine_PV:&amp;lt;TimeStart&amp;gt;,timer_01_c04 Waschmaschine_PV:&amp;lt;TimeEnd&amp;gt;,timer_02_c04&lt;br /&gt;
attr rg_Waschmaschine_Status DbLogExclude .*&lt;br /&gt;
attr rg_Waschmaschine_Status alias Status Waschmaschine Eigenverbrauch&lt;br /&gt;
attr rg_Waschmaschine_Status commands {state  =&amp;gt; &#039;state:on,off&#039;,\&lt;br /&gt;
PowerLevelMinTime =&amp;gt; &#039;PowerLevelMinTime:selectnumbers,30,30,300,0,lin&#039;,\&lt;br /&gt;
PowerLimitOn =&amp;gt; &#039;PowerLimitOn:selectnumbers,250,250,2000,0,lin&#039;,\&lt;br /&gt;
PowerLimitOff =&amp;gt; &#039;PowerLimitOff:selectnumbers,0,50,800,0,lin&#039;,\&lt;br /&gt;
RunTimeMin =&amp;gt; &#039;RunTimeMin:selectnumbers,300,300,7200,0,lin&#039;,\&lt;br /&gt;
RunTimePerDay =&amp;gt; &#039;RunTimePerDay:selectnumbers,7200,300,28800,0,lin&#039;,\&lt;br /&gt;
TimeStart =&amp;gt; &#039;TimeStart:time&#039;,\&lt;br /&gt;
TimeEnd =&amp;gt; &#039;TimeEnd:time&#039;}&lt;br /&gt;
attr rg_Waschmaschine_Status group PV Status&lt;br /&gt;
attr rg_Waschmaschine_Status nameStyle style=&amp;quot;color:grey&amp;quot;&lt;br /&gt;
attr rg_Waschmaschine_Status room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr rg_Waschmaschine_Status sortby 03&lt;br /&gt;
attr rg_Waschmaschine_Status style style=&amp;quot;font-size:18px&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Brunnenpumpe (mit extra Taster zum Aktivieren) ===&lt;br /&gt;
Das Beispiel für die Brunnenpumpe hat eine Besonderheit. Damit nicht vergessen wird die Brunnenpumpe nach der Benutzung wieder Stromlos zu schalten geschieht dies nach einer eingestellten Zeit, wenn sie nicht verwendet wurde. Also immer schön die Düse geöffnet halten :-) Des weitern kann die Pumpe über einen taster am Shelly2.5 aktiviert werden, was dem Elektriker gesagt werden sollte, damit er die Verdrahtung korrekt macht. Der Shelly2.5 aus diesem Beispiel wird ebenfalls für das nächste Beispiel verwendet, da die Steckdosen nebeneinander sind.&lt;br /&gt;
==== RAW Definition Brunnen (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen dummy&lt;br /&gt;
attr Brunnen DbLogExclude .*&lt;br /&gt;
attr Brunnen DbLogInclude state&lt;br /&gt;
attr Brunnen alias Brunnen&lt;br /&gt;
attr Brunnen comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen group PV Eigenverbrauch&lt;br /&gt;
attr Brunnen icon well&lt;br /&gt;
attr Brunnen readingList Brunnen_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Brunnen room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen setList Brunnen_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Brunnen sortby 13&lt;br /&gt;
attr Brunnen stateFormat state&lt;br /&gt;
attr Brunnen verbose 0&lt;br /&gt;
attr Brunnen webCmd Brunnen_Button&lt;br /&gt;
&lt;br /&gt;
setstate Brunnen off&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 Brunnen_Button off&lt;br /&gt;
setstate Brunnen 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Brunnen 2019-11-06 10:56:22 PowerLimitOff 600&lt;br /&gt;
setstate Brunnen 2020-04-20 13:06:04 PowerLimitOn 900&lt;br /&gt;
setstate Brunnen 2019-12-02 15:01:18 RunTimeMin 60&lt;br /&gt;
setstate Brunnen 2020-04-02 13:59:34 RunTimePerDay 10800&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:10 SetCmdOff set shelly05 off 0&lt;br /&gt;
setstate Brunnen 2020-01-01 16:29:24 SetCmdOn set shelly05 on 0&lt;br /&gt;
setstate Brunnen 2020-09-13 15:07:03 TimeEnd 09:00&lt;br /&gt;
setstate Brunnen 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Brunnen 2020-09-21 16:50:48 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Brunnen_Counter:pulseTimePerDay] &amp;gt;= [Brunnen:RunTimePerDay] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimeIncrement] &amp;gt;= [Brunnen:RunTimeMin] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and [Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn der Brunnen bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Brunnen:PowerLimitOff] and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Brunnen_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_3 : Brunnen stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##   Dies ist beim Brunnen nicht aktiv, um eine Überschwemmung zu vermeiden\&lt;br /&gt;
##   Es wird nur eine log Meldung geschrieben\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;gt; [Brunnen:PowerLimitOn] and\&lt;br /&gt;
  [Brunnen:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Brunnen:TimeStart]-[Brunnen:TimeEnd]] and\&lt;br /&gt;
  [Brunnen_Counter:pulseTimePerDay] &amp;lt; [Brunnen:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_4 : Brunnen freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose kann eingeschaltet werden&amp;quot;)}\&lt;br /&gt;
##     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Brunnens einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_5 : Brunnen manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Brunnen manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_6 : Brunnen manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn die Brunnenpumpe läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] &amp;gt; 600 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_7 : Brunnenpumpe läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe gestartet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Brunnenpumpe durch Druckschalter abschaltet\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_0] == 0 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_8 : Brunnenpumpe aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Brunnenpumpe abgeschaltet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn der Brunnen nicht gebraucht wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Brunnen:TimeEnd]-[Brunnen:TimeStart]] and\&lt;br /&gt;
  ([Brunnen:state] eq &amp;quot;on&amp;quot; or [shelly05:relay_0] eq &amp;quot;on&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Brunnen cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Brunnen&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Brunnen off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen Brunnen_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Brunnen_PV Brunnen_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Brunnen_PV DbLogExclude .*&lt;br /&gt;
attr Brunnen_PV DbLogInclude state,STATE,cmd.*,Device,Brunnen_Status,wait_timer&lt;br /&gt;
attr Brunnen_PV alias Brunnen_PV&lt;br /&gt;
attr Brunnen_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Brunnen manuell ein|Brunnen manuell aus|Brunnen laeuft|Brunnen aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Brunnen_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Brunnen_PV do always&lt;br /&gt;
attr Brunnen_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_PV icon well&lt;br /&gt;
attr Brunnen_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_PV sortby 31&lt;br /&gt;
attr Brunnen_PV stateFormat state : Brunnen_Status&lt;br /&gt;
attr Brunnen_PV verbose 0&lt;br /&gt;
attr Brunnen_PV wait 0:0:0:[Brunnen:PowerLevelMinTime]:0:30:0:60:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Die Einschaltung der Brunnenpumpe erfolgt mit Relais 1 . Am Shelly2.5 ist auch ein Taster verdrahtet, über den die Pumpe vor Ort aktiviert werden kann.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Brunnen_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Brunnen_Counter HourCounter shelly05:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Brunnen_Counter DbLogExclude .*&lt;br /&gt;
attr Brunnen_Counter alias Brunnen_Counter&lt;br /&gt;
attr Brunnen_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Brunnen_Counter event-on-change-reading .*&lt;br /&gt;
attr Brunnen_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Brunnen_Counter icon time_timer&lt;br /&gt;
attr Brunnen_Counter interval 5&lt;br /&gt;
attr Brunnen_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Brunnen_Counter sortby 33&lt;br /&gt;
attr Brunnen_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Accu laden ===&lt;br /&gt;
In diesem Beispiel wird der Accu eines Rasenroboters und in unserem Fall auch des E-Bikes an einer Steckdose geladen. Ziel ist es auch über den Winter immer wieder die Accus am Leben zu erhalten.&lt;br /&gt;
==== RAW Definition Shaun (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun dummy&lt;br /&gt;
attr Shaun DbLogExclude .*&lt;br /&gt;
attr Shaun DbLogInclude state&lt;br /&gt;
attr Shaun alias Shaun&lt;br /&gt;
attr Shaun comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun group PV Eigenverbrauch&lt;br /&gt;
attr Shaun icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun readingList Shaun_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Shaun room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun setList Shaun_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Shaun sortby 14&lt;br /&gt;
attr Shaun stateFormat state&lt;br /&gt;
attr Shaun verbose 0&lt;br /&gt;
attr Shaun webCmd Shaun_Button&lt;br /&gt;
&lt;br /&gt;
setstate Shaun off&lt;br /&gt;
setstate Shaun 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Shaun 2019-11-06 10:56:22 PowerLimitOff 100&lt;br /&gt;
setstate Shaun 2020-04-20 13:06:04 PowerLimitOn 300&lt;br /&gt;
setstate Shaun 2019-12-02 15:01:18 RunTimeMin 300&lt;br /&gt;
setstate Shaun 2020-04-02 13:59:34 RunTimePerDay 21600&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:10 SetCmdOff set shelly05 off 1&lt;br /&gt;
setstate Shaun 2020-01-01 16:29:24 SetCmdOn set shelly05 on 1&lt;br /&gt;
setstate Shaun 2020-10-21 12:30:05 Shaun_Button off&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:19 TimeEnd 15:00&lt;br /&gt;
setstate Shaun 2020-09-21 12:05:34 TimeStart 12:00&lt;br /&gt;
setstate Shaun 2020-10-21 14:00:38 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Shaun_Counter:pulseTimePerDay] &amp;gt;= [Shaun:RunTimePerDay] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimeIncrement] &amp;gt;= [Shaun:RunTimeMin] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and [Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Shaun Laden bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOff] and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Shaun_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_3 : Shaun stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;gt; [Shaun:PowerLimitOn] and\&lt;br /&gt;
  [Shaun:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Shaun:TimeStart]-[Shaun:TimeEnd]] and\&lt;br /&gt;
  [Shaun_Counter:pulseTimePerDay] &amp;lt; [Shaun:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_4 : Shaun freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung des Shaun einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Brunnen:Brunnen_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_5 : Shaun manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Shaun manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Shaun:Shaun_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_6 : Shaun manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Laden läuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;gt; 15 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_7 : Shaun läuft&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun wird geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose wenn Shaun geladen ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly05:power_1] &amp;lt;= 6 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_8 : Shaun aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Shaun hat geladen&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn es nicht mehr benötigt wird\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Shaun:PowerLimitOn] or\&lt;br /&gt;
   [[Shaun:TimeEnd]-[Shaun:TimeStart]] ) and\&lt;br /&gt;
   [Shaun:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
   [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Shaun cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Shaun&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Shaun off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun Shaun_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Shaun_PV Shaun_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Shaun_PV DbLogExclude .*&lt;br /&gt;
attr Shaun_PV DbLogInclude state,STATE,cmd.*,Device,Shaun_Status,wait_timer&lt;br /&gt;
attr Shaun_PV alias Shaun_PV&lt;br /&gt;
attr Shaun_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Shaun manuell ein|Shaun manuell aus|Shaun laed|Shaun aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Shaun_PV comment Version 2020.10.19 18:28&lt;br /&gt;
attr Shaun_PV do always&lt;br /&gt;
attr Shaun_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_PV icon scene_robo_lawnmower&lt;br /&gt;
attr Shaun_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_PV sortby 41&lt;br /&gt;
attr Shaun_PV stateFormat state : Shaun_Status&lt;br /&gt;
attr Shaun_PV verbose 0&lt;br /&gt;
attr Shaun_PV wait 0:0:0:[Shaun:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Signale (Shelly Modul: shelly2.5) ====&lt;br /&gt;
Für die Ladung der Accus wird hier das Relais 0 verwendet.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly05 Shelly &amp;lt;IP-Address&amp;gt;&lt;br /&gt;
attr shelly05 DbLogExclude .*&lt;br /&gt;
attr shelly05 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly05 alias Brunnen und Shaun&lt;br /&gt;
attr shelly05 comment Version 2020.10.19 18:28&lt;br /&gt;
attr shelly05 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly05 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly05 icon taster_ch_1&lt;br /&gt;
attr shelly05 interval 60&lt;br /&gt;
attr shelly05 mode relay&lt;br /&gt;
attr shelly05 model shelly2.5&lt;br /&gt;
attr shelly05 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly05 sortby 32&lt;br /&gt;
attr shelly05 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Brunnen Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Shaun Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly05 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly05 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Shaun_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Shaun_Counter HourCounter shelly05:power_1:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly05:power_1:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Shaun_Counter DbLogExclude .*&lt;br /&gt;
attr Shaun_Counter alias Shaun_Counter&lt;br /&gt;
attr Shaun_Counter comment Version 2020.10.19 18:28\&lt;br /&gt;
On und Off des Ladens werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Shaun_Counter event-on-change-reading .*&lt;br /&gt;
attr Shaun_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Shaun_Counter icon time_timer&lt;br /&gt;
attr Shaun_Counter interval 5&lt;br /&gt;
attr Shaun_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Shaun_Counter sortby 43&lt;br /&gt;
attr Shaun_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
Hier könnt Ihr Eure Fragen loswerden.&lt;br /&gt;
* {{Link2Forum|Topic=114849|Message=0}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal Plenticore; KSEM; BYD HV)&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Other Components]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=33940</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=33940"/>
		<updated>2020-09-16T08:33:37Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* RAW Definition DWD_Forecast */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore 10 Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Python3]]&lt;br /&gt;
&amp;lt;!-- |ModOwner=  --&amp;gt;&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Bild:Plenticore FHEM 1.png|mini|900px|rechts|Die Diagramme im Überblick]]&lt;br /&gt;
[[Bild:Plenticore FHEM 2.png|mini|900px|rechts|Geräte Überblick mit manueller Schaltmöglichkeit]]&lt;br /&gt;
[[Bild:Plenticore FHEM 3.png|mini|900px|rechts|Steuerungsgeräte für die Schaltlogik]]&lt;br /&gt;
[[Bild:Plenticore FHEM 4.png|mini|900px|rechts|ReadingsGroup für die schnelle Parametereinstellung]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus]] [https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/ Hersteller Link] ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen Energietechnik ==&lt;br /&gt;
&lt;br /&gt;
Der Wechselrichter, der Speicher und der KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
== Geräte-Registrierung ==&lt;br /&gt;
&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
&lt;br /&gt;
== Hersteller Dokumentation ==&lt;br /&gt;
&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2018/06/15/11/40/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2018/04/12/08/26/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2018/04/12/08/26/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2019/03/12/07/13/kostal_update_plenticore_piko_iq_011504581.swu/ Plenticore Plus - Software Update UI: 01.15.04581 FW: 01.43]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2018/08/30/08/53/ba_kostal_interface_modbus-tcp_sunspec.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2019/03/06/13/17/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2019/03/06/13/17/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/06/09/11/49/kostal_update_ksem_1_2_1.zip/ KSEM - Software Update - 1.2.1]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2019/05/09/13/57/ba_kostal_interface_ksem---201911.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
== Einbindung in das Netzwerk ==&lt;br /&gt;
&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen FHEM Umfeld ==&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte müssen mit TCP/IP erreichbar sein ===&lt;br /&gt;
&lt;br /&gt;
=== Alle Module sollten auf einem aktuellen Stand sein ===&lt;br /&gt;
&lt;br /&gt;
=== Python ===&lt;br /&gt;
&lt;br /&gt;
==== Ein Python 3 sollte vorhanden sein ====&lt;br /&gt;
Wenn man die erweiterten Funktionalitäten, wie Statistiken, Speicher auslesen und später auch das Setzen von Werten im Plenticore, verwenden möchte.&lt;br /&gt;
&lt;br /&gt;
==== Es müssen folgende Python Module vorhanden sein ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
python3-pip&lt;br /&gt;
&lt;br /&gt;
pip3 install pycryptodome&lt;br /&gt;
pip3 install -U fhem&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Eine LogDB/LogDBRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird. ===&lt;br /&gt;
&lt;br /&gt;
=== Verwendete Module ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Modbus&lt;br /&gt;
- HTTPMOD&lt;br /&gt;
- expandJSON&lt;br /&gt;
- DbLog&lt;br /&gt;
- DbRep&lt;br /&gt;
- dummy&lt;br /&gt;
- Shelly&lt;br /&gt;
- HourCounter&lt;br /&gt;
- readingsGroup&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Einbindung in FHEM: Überblick ==&lt;br /&gt;
&lt;br /&gt;
=== Hardware Anbindung (alles über LAN) ===&lt;br /&gt;
&lt;br /&gt;
==== Kostal Plenticore Plus ====&lt;br /&gt;
===== Kostal Plenticore Plus die Basis information (Modbus/TCP) =====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
====== Plenticore Modbus Definition ======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Modbus Timing ======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
====== RAW Definition des konfigurations Dummy ======&lt;br /&gt;
Diese Dummy soll alle Konfigurationsparameter halten, auf die dann die anderen Geräte Definitionen zentral zugreifen. Hier können auch default Namen und Vorschläge für Werte in Form von Slidern und Auswahllisten hinterlegt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Anlage_1_config dummy&lt;br /&gt;
attr PV_Anlage_1_config DbLogExclude .*&lt;br /&gt;
attr PV_Anlage_1_config alias PV_Anlage_1_config&lt;br /&gt;
attr PV_Anlage_1_config comment Steht das reading module_*_count auf 0 wird diese Ausrichtung nicht berücksichtigt\&lt;br /&gt;
Passworte zu dieser Konfiguration liegen im Dateiverzeichnis ~./python/pwd_*.json\&lt;br /&gt;
\&lt;br /&gt;
Korrekturkurven:\&lt;br /&gt;
         Steilheit  Parallel\&lt;br /&gt;
                    verschiebung\&lt;br /&gt;
tempk      -0.39      25\&lt;br /&gt;
cloudk     -0.65       0\&lt;br /&gt;
raink      -0.30       0\&lt;br /&gt;
Der Slider für die Steilheit wird mit - k/100 umgerechnet. 39 ==&amp;gt; -0.39&lt;br /&gt;
attr PV_Anlage_1_config event-on-change-reading .*&lt;br /&gt;
attr PV_Anlage_1_config group PV Eigenverbrauch&lt;br /&gt;
attr PV_Anlage_1_config icon solar_icon&lt;br /&gt;
attr PV_Anlage_1_config readingList IP-Address_Plenticore IP-Address_BYD IP-Address_KSEM IP-Address_FHEM module_1_active module_2_active module_3_active module_1_name module_2_name module_3_name module_1_direction module_2_direction module_3_direction module_1_count module_2_count module_3_count module_1_power module_2_power module_3_power module_1_plain module_2_plain module_3_plain forecast_cloudk forecast_cloudk_base forecast_raink forecast_raink_base forecast_tempk forecast_tempk_base forecast_factor Forecast_Station Battery_Total_Power&lt;br /&gt;
attr PV_Anlage_1_config room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Anlage_1_config setList IP-Address_Plenticore IP-Address_BYD IP-Address_KSEM IP-Address_FHEM module_1_name:East,SouthEast,South,SouthWest,West,Garage,CarPort module_2_name:East,SouthEast,South,SouthWest,West module_3_name:East,SouthEast,South,SouthWest,West module_1_direction:slider,-90,5,+90 module_2_direction:slider,-90,5,90 module_3_direction:slider,-90,5,90 module_1_count:slider,0,1,40 module_2_count:slider,0,1,40 module_3_count:slider,0,1,40 module_1_power:slider,250,10,400 module_2_power:slider,250,10,400 module_3_power:slider,250,10,400 module_1_plain:slider,15,1,45 module_2_plain:slider,15,1,45 module_3_plain:slider,15,1,45 forecast_cloudk:slider,0,1,100 forecast_cloudk_base:slider,0,1,10 forecast_raink:slider,0,1,100 forecast_raink_base:slider,0,1,10 forecast_tempk:slider,0,1,100 forecast_tempk_base:slider,10,1,30 forecast_factor:1,1.5,2,2.5,3,3.5,4,4.5,5 Forecast_Station Battery_Total_Power&lt;br /&gt;
attr PV_Anlage_1_config sortby 06&lt;br /&gt;
attr PV_Anlage_1_config verbose 0&lt;br /&gt;
&lt;br /&gt;
setstate PV_Anlage_1_config state&lt;br /&gt;
setstate PV_Anlage_1_config 2020-09-11 07:12:49 Battery_Total_Power 8960&lt;br /&gt;
setstate PV_Anlage_1_config 2020-09-11 07:36:39 Forecast_Station &amp;lt;Station&amp;gt;&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:44:46 IP-Address_BYD 192.168.178.10&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:39:26 IP-Address_FHEM 192.168.178.11&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:43:27 IP-Address_KSEM 192.168.178.12&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:39:44 IP-Address_Plenticore 192.168.178.13&lt;br /&gt;
setstate PV_Anlage_1_config 2020-09-02 18:39:15 forecast_cloudk 20&lt;br /&gt;
setstate PV_Anlage_1_config 2020-09-03 11:43:57 forecast_cloudk_base 0&lt;br /&gt;
setstate PV_Anlage_1_config 2020-09-02 18:40:29 forecast_raink 20&lt;br /&gt;
setstate PV_Anlage_1_config 2020-09-01 12:52:40 forecast_raink_base 0&lt;br /&gt;
setstate PV_Anlage_1_config 2020-09-01 12:46:57 forecast_tempk 39&lt;br /&gt;
setstate PV_Anlage_1_config 2020-09-01 12:50:06 forecast_tempk_base 25&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:27:30 module_1_count 0&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:27:38 module_1_direction -90&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:27:48 module_1_name East&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:29:42 module_1_plain 40&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:31:09 module_1_power 300&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:31:21 module_2_count 0&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:33:55 module_2_direction 0&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:34:03 module_2_name South&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:34:14 module_2_plain 40&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:34:25 module_2_power 300&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:34:42 module_3_count 0&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:34:50 module_3_direction 90&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:35:00 module_3_name West&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:35:08 module_3_plain 40&lt;br /&gt;
setstate PV_Anlage_1_config 2020-08-31 12:35:16 module_3_power 300&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== RAW Definition des Wechselrichters ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Anlage_1 ModbusAttr 71 60 &amp;lt;IP-Address_Plenticore&amp;gt;:1502 TCP&lt;br /&gt;
attr PV_Anlage_1 DbLogExclude .*&lt;br /&gt;
attr PV_Anlage_1 DbLogInclude Act_state_of_charge,Actual_battery_charge_-minus_or_discharge_-plus_Power,Actual_battery_charge_usable_Power,Battery_temperature,Home_own_consumption_from_PV,Home_own_consumption_from_battery,Home_own_consumption_from_grid,Inverter_state,Power_DC1,Power_DC2,Power_DC_Sum,Total_DC_Power,Total_DC_Power_Max,Total_PV_Power_reserve,Voltage_DC1,Voltage_DC2,.*_yield,Solar_.*&lt;br /&gt;
attr PV_Anlage_1 alias PV_Einspeisung&lt;br /&gt;
attr PV_Anlage_1 comment Kostal Plenticore 10 Plus mit BYD Speicher&lt;br /&gt;
attr PV_Anlage_1 dev-h-defFormat %.2f&lt;br /&gt;
attr PV_Anlage_1 dev-h-defLen 2&lt;br /&gt;
attr PV_Anlage_1 dev-h-defPoll 1&lt;br /&gt;
attr PV_Anlage_1 dev-h-defRevRegs 1&lt;br /&gt;
attr PV_Anlage_1 dev-h-defUnpack f&amp;gt;&lt;br /&gt;
attr PV_Anlage_1 dev-type-STR-format %s&lt;br /&gt;
attr PV_Anlage_1 dev-type-STR-len 8&lt;br /&gt;
attr PV_Anlage_1 dev-type-STR-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 dev-type-STR-unpack a*&lt;br /&gt;
attr PV_Anlage_1 event-on-change-reading Act_state_of_charge,Actual_battery_charge_.*,Battery_temperature,Home_own_consumption_from_.*,Inverter_state,Power_DC1,Power_DC2,Power_DC_Sum,Total_DC_Power,Total_DC_Power_Max,Total_PV_Power_reserve,Voltage_DC1,Voltage_DC2,.*_yield,Solar_.*&lt;br /&gt;
attr PV_Anlage_1 group PV Eigenverbrauch&lt;br /&gt;
attr PV_Anlage_1 icon sani_solar&lt;br /&gt;
attr PV_Anlage_1 obj-h100-reading Total_DC_Power&lt;br /&gt;
attr PV_Anlage_1 obj-h104-format %s&lt;br /&gt;
attr PV_Anlage_1 obj-h104-reading State_of_energy_manager&lt;br /&gt;
attr PV_Anlage_1 obj-h104-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 obj-h104-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h106-reading Home_own_consumption_from_battery&lt;br /&gt;
attr PV_Anlage_1 obj-h108-reading Home_own_consumption_from_grid&lt;br /&gt;
attr PV_Anlage_1 obj-h110-reading Total_home_consumption_Battery&lt;br /&gt;
attr PV_Anlage_1 obj-h112-reading Total_home_consumption_Grid&lt;br /&gt;
attr PV_Anlage_1 obj-h114-reading Total_home_consumption_PV&lt;br /&gt;
attr PV_Anlage_1 obj-h116-reading Home_own_consumption_from_PV&lt;br /&gt;
attr PV_Anlage_1 obj-h118-reading Total_home_consumption&lt;br /&gt;
attr PV_Anlage_1 obj-h120-reading Isolation_resistance&lt;br /&gt;
attr PV_Anlage_1 obj-h122-reading Power_limit_from_EVU&lt;br /&gt;
attr PV_Anlage_1 obj-h124-reading Total_home_consumption_rate&lt;br /&gt;
attr PV_Anlage_1 obj-h14-reading Inverter_serial_number&lt;br /&gt;
attr PV_Anlage_1 obj-h14-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h144-reading Worktime&lt;br /&gt;
attr PV_Anlage_1 obj-h150-reading Actual_cos_phi&lt;br /&gt;
attr PV_Anlage_1 obj-h152-reading Grid_frequency&lt;br /&gt;
attr PV_Anlage_1 obj-h154-reading Current_Phase_1&lt;br /&gt;
attr PV_Anlage_1 obj-h156-reading Active_power_Phase_1&lt;br /&gt;
attr PV_Anlage_1 obj-h158-reading Voltage_Phase_1&lt;br /&gt;
attr PV_Anlage_1 obj-h160-reading Current_Phase_2&lt;br /&gt;
attr PV_Anlage_1 obj-h162-reading Active_power_Phase_2&lt;br /&gt;
attr PV_Anlage_1 obj-h164-reading Voltage_Phase_2&lt;br /&gt;
attr PV_Anlage_1 obj-h166-reading Current_Phase_3&lt;br /&gt;
attr PV_Anlage_1 obj-h168-reading Active_power_Phase_3&lt;br /&gt;
attr PV_Anlage_1 obj-h170-reading Voltage_Phase_3&lt;br /&gt;
attr PV_Anlage_1 obj-h172-reading Total_AC_active_power&lt;br /&gt;
attr PV_Anlage_1 obj-h174-reading Total_AC_reactive_power&lt;br /&gt;
attr PV_Anlage_1 obj-h178-reading Total_AC_apparent_power&lt;br /&gt;
attr PV_Anlage_1 obj-h190-reading Battery_charge_current&lt;br /&gt;
attr PV_Anlage_1 obj-h194-format %.0f&lt;br /&gt;
attr PV_Anlage_1 obj-h194-reading Number_of_battery_cycles&lt;br /&gt;
attr PV_Anlage_1 obj-h200-reading Actual_battery_charge_-minus_or_discharge_-plus_current&lt;br /&gt;
attr PV_Anlage_1 obj-h202-reading PSSB_fuse_state&lt;br /&gt;
attr PV_Anlage_1 obj-h208-format %.0f&lt;br /&gt;
attr PV_Anlage_1 obj-h208-reading Battery_ready_flag&lt;br /&gt;
attr PV_Anlage_1 obj-h210-reading Act_state_of_charge&lt;br /&gt;
attr PV_Anlage_1 obj-h212-reading Battery_state&lt;br /&gt;
attr PV_Anlage_1 obj-h214-reading Battery_temperature&lt;br /&gt;
attr PV_Anlage_1 obj-h216-reading Battery_voltage&lt;br /&gt;
attr PV_Anlage_1 obj-h218-reading Cos_phi_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h220-reading Frequency_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h222-reading Current_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h224-reading Active_power_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h226-reading Reactive_power_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h228-reading Apparent_power_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h230-reading Voltage_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h232-reading Current_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h234-reading Active_power_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h236-reading Reactive_power_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h238-reading Apparent_power_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h240-reading Voltage_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h242-reading Current_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h244-reading Active_power_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h246-reading Reactive_power_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h248-reading Apparent_power_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h250-reading Voltage_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h252-reading Total_active_power_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h254-reading Total_reactive_power_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h256-reading Total_apparent_power_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h258-reading Current_DC1&lt;br /&gt;
attr PV_Anlage_1 obj-h260-reading Power_DC1&lt;br /&gt;
attr PV_Anlage_1 obj-h266-reading Voltage_DC1&lt;br /&gt;
attr PV_Anlage_1 obj-h268-reading Current_DC2&lt;br /&gt;
attr PV_Anlage_1 obj-h270-reading Power_DC2&lt;br /&gt;
attr PV_Anlage_1 obj-h276-reading Voltage_DC2&lt;br /&gt;
attr PV_Anlage_1 obj-h278-reading Current_DC3&lt;br /&gt;
attr PV_Anlage_1 obj-h280-reading Power_DC3&lt;br /&gt;
attr PV_Anlage_1 obj-h286-reading Voltage_DC3&lt;br /&gt;
attr PV_Anlage_1 obj-h320-reading Total_yield&lt;br /&gt;
attr PV_Anlage_1 obj-h322-reading Daily_yield&lt;br /&gt;
attr PV_Anlage_1 obj-h324-reading Yearly_yield&lt;br /&gt;
attr PV_Anlage_1 obj-h326-reading Monthly_yield&lt;br /&gt;
attr PV_Anlage_1 obj-h38-reading Software-Version_Maincontroller_(MC)&lt;br /&gt;
attr PV_Anlage_1 obj-h38-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h384-len 16&lt;br /&gt;
attr PV_Anlage_1 obj-h384-reading Inverter_network_name&lt;br /&gt;
attr PV_Anlage_1 obj-h384-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h420-reading IP-address&lt;br /&gt;
attr PV_Anlage_1 obj-h420-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h428-reading IP-subnetmask&lt;br /&gt;
attr PV_Anlage_1 obj-h428-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h436-reading IP-gateway&lt;br /&gt;
attr PV_Anlage_1 obj-h436-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h446-reading IP-DNS1&lt;br /&gt;
attr PV_Anlage_1 obj-h446-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h454-reading IP-DNS2&lt;br /&gt;
attr PV_Anlage_1 obj-h454-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h46-reading Software-Version_IO-Controller_(IOC)&lt;br /&gt;
attr PV_Anlage_1 obj-h46-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h514-len 1&lt;br /&gt;
attr PV_Anlage_1 obj-h514-reading Battery_actual_SOC&lt;br /&gt;
attr PV_Anlage_1 obj-h517-reading Battery_Manufacturer&lt;br /&gt;
attr PV_Anlage_1 obj-h517-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h525-format %c&lt;br /&gt;
attr PV_Anlage_1 obj-h525-reading Battery_Model_ID&lt;br /&gt;
attr PV_Anlage_1 obj-h525-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h527-format %c&lt;br /&gt;
attr PV_Anlage_1 obj-h527-reading Battery_Serial_Number&lt;br /&gt;
attr PV_Anlage_1 obj-h529-len 4&lt;br /&gt;
attr PV_Anlage_1 obj-h529-reading Work_Capacity&lt;br /&gt;
attr PV_Anlage_1 obj-h529-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h531-format %.0f&lt;br /&gt;
attr PV_Anlage_1 obj-h531-reading Inverter_Max_Power&lt;br /&gt;
attr PV_Anlage_1 obj-h531-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h535-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 obj-h535-unpack n&lt;br /&gt;
attr PV_Anlage_1 obj-h551-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 obj-h559-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 obj-h56-format %.0f&lt;br /&gt;
attr PV_Anlage_1 obj-h56-reading Inverter_state&lt;br /&gt;
attr PV_Anlage_1 obj-h56-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h575-len 1&lt;br /&gt;
attr PV_Anlage_1 obj-h575-reading Inverter_Generation_Power_(actual)&lt;br /&gt;
attr PV_Anlage_1 obj-h577-len 2&lt;br /&gt;
attr PV_Anlage_1 obj-h577-reading Generation_Energy&lt;br /&gt;
attr PV_Anlage_1 obj-h577-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h578-reading Total_energy&lt;br /&gt;
attr PV_Anlage_1 obj-h582-reading Actual_battery_charge-discharge_power&lt;br /&gt;
attr PV_Anlage_1 obj-h586-format %s&lt;br /&gt;
attr PV_Anlage_1 obj-h586-reading Battery_Firmware&lt;br /&gt;
attr PV_Anlage_1 obj-h586-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h588-format %s&lt;br /&gt;
attr PV_Anlage_1 obj-h588-len 1&lt;br /&gt;
attr PV_Anlage_1 obj-h588-reading Battery_Type&lt;br /&gt;
attr PV_Anlage_1 obj-h588-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h6-reading Inverter_article_number&lt;br /&gt;
attr PV_Anlage_1 obj-h6-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h768-len 32&lt;br /&gt;
attr PV_Anlage_1 obj-h768-reading Productname&lt;br /&gt;
attr PV_Anlage_1 obj-h768-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h800-len 32&lt;br /&gt;
attr PV_Anlage_1 obj-h800-reading Power_class&lt;br /&gt;
attr PV_Anlage_1 obj-h800-type STR&lt;br /&gt;
attr PV_Anlage_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Anlage_1 sortby 01&lt;br /&gt;
attr PV_Anlage_1 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TH ALIGN=\&amp;quot;MIDDLE\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;Batterie %s&amp;lt;/TH&amp;gt;\&lt;br /&gt;
  &amp;lt;TH ALIGN=\&amp;quot;MIDDLE\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;aktuell&amp;lt;/TH&amp;gt;\&lt;br /&gt;
  &amp;lt;TH ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;Hausverbrauch&amp;lt;/TH&amp;gt;\&lt;br /&gt;
  &amp;lt;TH ALIGN=\&amp;quot;MIDDLE\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;Erträge&amp;lt;/TH&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD ALIGN=\&amp;quot;MIDDLE\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;\&lt;br /&gt;
    Leistung:  %04d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    Temp.: %02.1f °C&amp;lt;br&amp;gt;\&lt;br /&gt;
    Ladung total: %2d %%&amp;lt;br&amp;gt;\&lt;br /&gt;
    Ladung Res.: %04d Wh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;\&lt;br /&gt;
    DC total: %05d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    &amp;lt;br&amp;gt;\&lt;br /&gt;
    &amp;lt;br&amp;gt;\&lt;br /&gt;
    PV reserve: %05d W\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;\&lt;br /&gt;
    von PV: %05d W &amp;lt;br&amp;gt;\&lt;br /&gt;
    von Batterie: %05d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    vom Netz: %05d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    ins Haus: %05d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    Netz: %05d W\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;\&lt;br /&gt;
    Tag: %05d KWh &amp;lt;br&amp;gt;\&lt;br /&gt;
    Monat: %05d KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Jahr: %05d KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Total: %05d KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; , \&lt;br /&gt;
(ReadingsVal($name,&amp;quot;Actual_battery_charge_-minus_or_discharge_-plus_Power&amp;quot;,0) lt 0) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;Laden&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Entladen&amp;lt;/span&amp;gt;&amp;quot; ,\&lt;br /&gt;
\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Actual_battery_charge_-minus_or_discharge_-plus_Power&amp;quot;,0),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Battery_temperature&amp;quot;,0) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Act_state_of_charge&amp;quot;,0) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Actual_battery_charge_usable_Power&amp;quot;,0) ,\&lt;br /&gt;
\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Power_DC_Sum&amp;quot;,&amp;quot;0&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Total_PV_Power_reserve&amp;quot;,&amp;quot;0&amp;quot;),\&lt;br /&gt;
\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Home_own_consumption_from_PV&amp;quot;,0) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Home_own_consumption_from_battery&amp;quot;,0) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Home_own_consumption_from_grid&amp;quot;,0),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Home_own_consumption_from_PV&amp;quot;,0) +ReadingsVal($name,&amp;quot;Home_own_consumption_from_battery&amp;quot;,0)+ReadingsVal($name,&amp;quot;Home_own_consumption_from_grid&amp;quot;,0),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0),\&lt;br /&gt;
\&lt;br /&gt;
round(ReadingsVal($name,&amp;quot;Daily_yield&amp;quot;,0)/1000 ,0),\&lt;br /&gt;
round(ReadingsVal($name,&amp;quot;Monthly_yield&amp;quot;,0)/1000 ,0) ,\&lt;br /&gt;
round(ReadingsVal($name,&amp;quot;Yearly_yield&amp;quot;,0)/1000 ,0) ,\&lt;br /&gt;
round(ReadingsVal($name,&amp;quot;Total_yield&amp;quot;,0)/1000 ,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr PV_Anlage_1 userReadings Power_DC_Sum:Total_DC_Power.* { ReadingsVal($NAME,&amp;quot;Power_DC1&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal($NAME,&amp;quot;Power_DC2&amp;quot;,&amp;quot;0&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
Total_PV_Power_reserve:Total_DC_Power.* {my $reserve = ReadingsVal($NAME,&amp;quot;Power_DC_Sum&amp;quot;,&amp;quot;0&amp;quot;) * 0.90 - ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_PV&amp;quot;,&amp;quot;0&amp;quot;);;;; ($reserve lt 0)?0:round($reserve,3)  },\&lt;br /&gt;
\&lt;br /&gt;
Total_DC_Power_Max:Total_DC_Power.* { my $Bat_out = (ReadingsVal($NAME,&amp;quot;Actual_battery_charge_-minus_or_discharge_-plus_current&amp;quot;,&amp;quot;0&amp;quot;)*ReadingsVal($NAME,&amp;quot;Battery_voltage&amp;quot;,&amp;quot;0&amp;quot;));;;; ($Bat_out gt 0)?ReadingsVal($NAME,&amp;quot;Power_DC_Sum&amp;quot;,&amp;quot;0&amp;quot;) + $Bat_out :ReadingsVal($NAME,&amp;quot;Power_DC_Sum&amp;quot;,&amp;quot;0&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
Actual_battery_charge_-minus_or_discharge_-plus_Power:Actual_battery_charge_-minus_or_discharge_-plus_current.* {round((ReadingsVal($NAME,&amp;quot;Actual_battery_charge_-minus_or_discharge_-plus_current&amp;quot;,&amp;quot;0&amp;quot;)*ReadingsVal($NAME,&amp;quot;Battery_voltage&amp;quot;,&amp;quot;0&amp;quot;)),0)},\&lt;br /&gt;
\&lt;br /&gt;
Actual_battery_charge_usable_Power:Act_state_of_charge.* {my $x = (ReadingsVal($NAME.&amp;quot;_config&amp;quot;,Battery_Total_Power&amp;quot;,&amp;quot;0&amp;quot;)*(ReadingsVal($NAME,&amp;quot;Act_state_of_charge&amp;quot;,&amp;quot;0&amp;quot;)-10)/100);;;; ($x lt 0)?0:round($x,0) }&lt;br /&gt;
attr PV_Anlage_1 verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Userreadings ======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userreadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind. Dies betrifft insbesondere die Statistics_* readings, die durch ein Python Skript später erzeugt werden.&lt;br /&gt;
&lt;br /&gt;
Power_DC_Sum&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Dies berechnet direkt die Summe der DC-Leistung. Wenn der Plenticore einen Speicher hat, wird dieser am String 3 angeschlossen,&lt;br /&gt;
   sollte also kein Speicher vorhanden sein muss man hier den dritten String auch noch addieren.&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers über das PV_Anlage_1_config Gerät&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
&lt;br /&gt;
===== Kostal Plenticore Plus die API (über HTTPMOD mit Python Skript Authentifizierung) =====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Für diesen API Zugang über HTTP steht nun ein neues Gerät zur Verfügung, dass mit HTTPMOD und Python Authentifizierungsskripten die mehrstufige Anmeldung durchführt. Das ganze soll in Zukunft den starren Zugriff auf die Statistiken ablösen und eine Erweiterung zum setzen von Parametern im Plenticore bieten.&lt;br /&gt;
&lt;br /&gt;
====== Umstellungsaufwand, falls jemand früher eingestiegen ist. ======&lt;br /&gt;
Die erste Folge für den Umstieg ist, dass die Statistiken nicht mehr im PV_Anlage_1 Gerät abgelegt werden, da diese ja teil der API Abfrage sind. Das muss dann in der Bilanz berücksichtigt werden, da die Einträge dann unter dem neuen PV_Anlage_1_API Gerät abgelegt werden.&lt;br /&gt;
&lt;br /&gt;
2020.09.06 Die Umstellung auf das Plenticore API Gerät hat begonnen&lt;br /&gt;
&lt;br /&gt;
- Die Bilanz RAW Definition wurde aktualisiert&lt;br /&gt;
&lt;br /&gt;
- In der PV_Schedule Definition wurde das Kommando für die Aktualisierung der Statistik auf PV_Anlage_1_API umgestellt&lt;br /&gt;
&lt;br /&gt;
- Das Logging von Dum.Energy läuft wie gehabt weiter&lt;br /&gt;
&lt;br /&gt;
- Die Statistic_* readings aus dem PV_Anlage_1 Gerät können in der SQL Datenbank zum neuen PV_Anlage_1_API Gerät verschoben werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Bitte zuerst den Zeitraum, in dem die Statistikeinträge in die Datenbank geschrieben wurden feststellen.&lt;br /&gt;
MySQL [fhem]&amp;gt; SELECT TIMESTAMP,DEVICE,READING,VALUE FROM history WHERE DEVICE=&#039;PV_Anlage_1_API&#039; AND READING LIKE &#039;Statistic_%&#039; AND TIMESTAMP &amp;gt; &#039;2020-07-01 00:00:00&#039; ORDER BY TIMESTAMP LIMIT 500;&lt;br /&gt;
## Für den Update dann din Zeitraum so weit es geht einschränken, damit die Laufzeit in der Datenbank nicht so hoch wird.&lt;br /&gt;
MySQL [fhem]&amp;gt; UPDATE history SET TIMESTAMP=TIMESTAMP, DEVICE=&#039;PV_Anlage_1_API&#039; WHERE DEVICE=&#039;PV_Anlage_1&#039; AND READING LIKE &#039;Statistic_%&#039; AND TIMESTAMP &amp;gt; &#039;2020-07-01 00:00:00&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- Die alten Statistic_* readings können nun aus dem PV_Anlage_1 Gerät entfernt werden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
deletereading PV_Anlage_1 Statistic_.*&lt;br /&gt;
deletereading PV_Anlage_1 statistics_.*&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- Für das Logging kann nun im Attribut &amp;quot;DbLogInclude&amp;quot; ebenfalls &amp;quot;Statistic_.*&amp;quot; entfernt werden&lt;br /&gt;
&lt;br /&gt;
- Beim Attribut &amp;quot;event-on-change-reading&amp;quot; sind auch &amp;quot;statistics_.*,Statistic_.*&amp;quot; zu entfernen&lt;br /&gt;
&lt;br /&gt;
- Das userreading im PV_Anlage_1 kann ebenfalls geändert werden und um diese Zeile verkürzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
statistics_clean:statistics_output.* { my $x =  ReadingsVal($NAME,&amp;quot;statistics_output&amp;quot;,0);; $x =~ s/&amp;quot;moduleid&amp;quot;: &amp;quot;scb:statistic:EnergyFlow&amp;quot;, |, &amp;quot;moduleid&amp;quot;: &amp;quot;scb:statistic:EnergyFlow&amp;quot;|&amp;quot;processdata&amp;quot;: \[//g;; $x =~ s/id&amp;quot;: &amp;quot;|, &amp;quot;unit&amp;quot;: &amp;quot;&amp;quot;, &amp;quot;value&amp;quot;|^\[|\]\}\]$//g;; $x =~ s/moduleid/statistics_00_moduleid/g;; $x =~ s/processdata/statistics/g;; $x =~ s/\}\, \{/\, /g;; $x =~ s/\{\{/\{/g;; return $x }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- Nun noch das Gerät Plenticore_Statistics für das expandJSON löschen&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
delete Plenticore_Statistics&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Das sollten nun alle erforderlichen Bereinigungen für den Wechsel auf das PV_Anlage_1_API Gerät sein.&lt;br /&gt;
&lt;br /&gt;
====== Plenticore API ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Dateiverzeichnis ======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/fhem&lt;br /&gt;
/opt/fhem/python/pwd_fhem.json&lt;br /&gt;
/opt/fhem/python/pwd_plenticore.json&lt;br /&gt;
/opt/fhem/python/bin&lt;br /&gt;
/opt/fhem/python/bin/plenticore_auth_finish.py&lt;br /&gt;
/opt/fhem/python/bin/plenticore_auth_session.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Python 3 ======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ which python3&lt;br /&gt;
/usr/bin/python3&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ python3 --version&lt;br /&gt;
Python 3.7.3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Passworte ======&lt;br /&gt;
Die Passworte für den Plenticore und den FHEM Zugang liegen in einzelnen JSON Dateien&lt;br /&gt;
&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_plenticore.json&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;,&lt;br /&gt;
    &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Steht auf dem Gehäuse&amp;gt;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_fhem.json&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;username&amp;quot;: &amp;quot;&amp;lt;Ein Fhem Telnet User&amp;gt;&amp;quot;,&lt;br /&gt;
    &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Das Passwort des Users&amp;gt;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== plenticore_auth_* Erläuterung ======&lt;br /&gt;
Die folgenden beiden Skripte sind ein Extrakt aus den bisherigen Skripten, ohne die HTTP Aufrufe. Sie dienen nur noch der Generierung von Authentifizierungsschlüsseln. Optimaler Weise müssten sie auch noch nach Perl konvertiert werden, was für später geplant ist.&lt;br /&gt;
Als Übergabeparameter werden aus dem PV_Anlage_1_API Gerät Rückgabewerte der HTTP Aufrufe verwendet.&lt;br /&gt;
&lt;br /&gt;
====== plenticore_auth_finish ======&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ cat plenticore_auth_finish.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import string&lt;br /&gt;
import base64&lt;br /&gt;
import hashlib&lt;br /&gt;
import hmac&lt;br /&gt;
from Crypto.Cipher import AES&lt;br /&gt;
import binascii&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
import json&lt;br /&gt;
import fhem&lt;br /&gt;
&lt;br /&gt;
web          = sys.argv[1]&lt;br /&gt;
randomString = sys.argv[2]&lt;br /&gt;
nonce        = sys.argv[3]&lt;br /&gt;
salt         = sys.argv[4]&lt;br /&gt;
rounds       = sys.argv[5]&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_plenticore.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
PASSWD = credentials[&amp;quot;password&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
u       = randomString&lt;br /&gt;
&lt;br /&gt;
#u       = base64.b64encode(u.encode(&#039;utf-8&#039;)).decode(&#039;utf-8&#039;)&lt;br /&gt;
#print(&amp;quot;randomString: &amp;quot;,u)&lt;br /&gt;
&lt;br /&gt;
i       = nonce&lt;br /&gt;
o       = int(rounds)&lt;br /&gt;
a       = salt&lt;br /&gt;
bitSalt = base64.b64decode(a)&lt;br /&gt;
&lt;br /&gt;
#print(&amp;quot;nonce       : &amp;quot;,i)&lt;br /&gt;
#print(&amp;quot;salt        : &amp;quot;,a)&lt;br /&gt;
#print(&amp;quot;rounds      : &amp;quot;,o)&lt;br /&gt;
&lt;br /&gt;
def getPBKDF2Hash(password, bytedSalt, rounds):&lt;br /&gt;
    return hashlib.pbkdf2_hmac(&#039;sha256&#039;, password.encode(&#039;utf-8&#039;), bytedSalt, rounds)&lt;br /&gt;
&lt;br /&gt;
r = getPBKDF2Hash(PASSWD,bitSalt,o)&lt;br /&gt;
s = hmac.new(r, &amp;quot;Client Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
c = hmac.new(r, &amp;quot;Server Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
_ = hashlib.sha256(s).digest()&lt;br /&gt;
d = &amp;quot;n=user,r=&amp;quot;+u+&amp;quot;,r=&amp;quot;+i+&amp;quot;,s=&amp;quot;+a+&amp;quot;,i=&amp;quot;+str(o)+&amp;quot;,c=biws,r=&amp;quot;+i&lt;br /&gt;
g = hmac.new(_, d.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
p = hmac.new(c, d.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
f = bytes(a ^ b for (a, b) in zip(s, g))&lt;br /&gt;
proof = base64.b64encode(f).decode(&#039;utf-8&#039;)&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_fhem.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
fh = fhem.Fhem(web, protocol=&amp;quot;http&amp;quot;, port=8083, username=credentials[&amp;quot;username&amp;quot;], password=credentials[&amp;quot;password&amp;quot;])&lt;br /&gt;
&lt;br /&gt;
fh.send_cmd(&amp;quot;setreading PV_Anlage_1_API auth_proof &amp;quot; + proof)&lt;br /&gt;
&lt;br /&gt;
#print(&amp;quot;proof       : &amp;quot;,proof)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====== plenticore_auth_session ======&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ cat plenticore_auth_session.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import string&lt;br /&gt;
import base64&lt;br /&gt;
import hashlib&lt;br /&gt;
import os&lt;br /&gt;
import hmac&lt;br /&gt;
from Crypto.Cipher import AES&lt;br /&gt;
import binascii&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
import json&lt;br /&gt;
import fhem&lt;br /&gt;
&lt;br /&gt;
web          = sys.argv[1]&lt;br /&gt;
randomString = sys.argv[2]&lt;br /&gt;
nonce        = sys.argv[3]&lt;br /&gt;
salt         = sys.argv[4]&lt;br /&gt;
rounds       = sys.argv[5]&lt;br /&gt;
token        = sys.argv[6]&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_plenticore.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
PASSWD = credentials[&amp;quot;password&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
u       = randomString&lt;br /&gt;
i       = nonce&lt;br /&gt;
o       = int(rounds)&lt;br /&gt;
a       = salt&lt;br /&gt;
bitSalt = base64.b64decode(a)&lt;br /&gt;
&lt;br /&gt;
def getPBKDF2Hash(password, bytedSalt, rounds):&lt;br /&gt;
    return hashlib.pbkdf2_hmac(&#039;sha256&#039;, password.encode(&#039;utf-8&#039;), bytedSalt, rounds)&lt;br /&gt;
&lt;br /&gt;
r = getPBKDF2Hash(PASSWD,bitSalt,o)&lt;br /&gt;
&lt;br /&gt;
#print(&amp;quot;randomString: &amp;quot;,u)&lt;br /&gt;
#print(&amp;quot;nonce       : &amp;quot;,i)&lt;br /&gt;
#print(&amp;quot;salt        : &amp;quot;,a)&lt;br /&gt;
#print(&amp;quot;rounds      : &amp;quot;,o)&lt;br /&gt;
#print(&amp;quot;token       : &amp;quot;,token)&lt;br /&gt;
&lt;br /&gt;
s = hmac.new(r, &amp;quot;Client Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
_ = hashlib.sha256(s).digest()&lt;br /&gt;
d = &amp;quot;n=user,r=&amp;quot;+u+&amp;quot;,r=&amp;quot;+i+&amp;quot;,s=&amp;quot;+a+&amp;quot;,i=&amp;quot;+str(o)+&amp;quot;,c=biws,r=&amp;quot;+i&lt;br /&gt;
&lt;br /&gt;
y = hmac.new(_, &amp;quot;Session Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256)&lt;br /&gt;
y.update(d.encode(&#039;utf-8&#039;))&lt;br /&gt;
y.update(s)&lt;br /&gt;
P = y.digest()&lt;br /&gt;
protocol_key = P&lt;br /&gt;
t = os.urandom(16)&lt;br /&gt;
&lt;br /&gt;
e2          = AES.new(protocol_key,AES.MODE_GCM,t)&lt;br /&gt;
e2, authtag = e2.encrypt_and_digest(token.encode(&#039;utf-8&#039;))&lt;br /&gt;
&lt;br /&gt;
iv      = base64.b64encode(t).decode(&#039;utf-8&#039;)&lt;br /&gt;
authtag = base64.b64encode(authtag).decode(&amp;quot;utf-8&amp;quot;)&lt;br /&gt;
payload = base64.b64encode(e2).decode(&#039;utf-8&#039;)&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_fhem.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
fh = fhem.Fhem(web, protocol=&amp;quot;http&amp;quot;, port=8083, username=credentials[&amp;quot;username&amp;quot;], password=credentials[&amp;quot;password&amp;quot;])&lt;br /&gt;
&lt;br /&gt;
fh.send_cmd(&amp;quot;setreading PV_Anlage_1_API auth_iv &amp;quot; + iv)&lt;br /&gt;
fh.send_cmd(&amp;quot;setreading PV_Anlage_1_API auth_authtag &amp;quot; + authtag)&lt;br /&gt;
fh.send_cmd(&amp;quot;setreading PV_Anlage_1_API auth_payload &amp;quot; + payload)&lt;br /&gt;
&lt;br /&gt;
#print(&amp;quot;iv          : &amp;quot;,iv)&lt;br /&gt;
#print(&amp;quot;authtag     : &amp;quot;,authtag)&lt;br /&gt;
#print(&amp;quot;payload     : &amp;quot;,payload)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablaufbeschreibung PV_Anlage_1_API ======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit dem ersten Aufruf und läuft dann vollautomatisch bis zur Rückgabe der auth_sessionId&lt;br /&gt;
   1. get PV_Anlage_1_API 01/auth/start&lt;br /&gt;
* auth_randomString64 - wird generiert&lt;br /&gt;
* /api/v1/auth/start - HTTP request erfolgt&lt;br /&gt;
* auth_nonce, auth_salt, auth_rounds werden empfangen&lt;br /&gt;
   2. auth_Step1_Message:auth_nonce.* wird getriggert&lt;br /&gt;
* plenticore_auth_finish.py wird ausgeführt&lt;br /&gt;
* auth_proof - wird berechnet&lt;br /&gt;
   3. auth_Step2_Message:auth_proof.* wird getriggert&lt;br /&gt;
* Start von 02_/auth/finish&lt;br /&gt;
   4. get PV_Anlage_1_API 02_/auth/finish&lt;br /&gt;
* /api/v1/auth/finish - HTTP request erfolgt&lt;br /&gt;
* auth_signature, auth_token werden empfangen&lt;br /&gt;
   5. auth_Step3_Message:auth_token.* wird getriggert&lt;br /&gt;
* plenticore_auth_session.py wird ausgeführt&lt;br /&gt;
* auth_iv, auth_authtag, auth_payload - wird berechnet&lt;br /&gt;
   6. auth_Step4_Message:auth_payload.* wird getriggert&lt;br /&gt;
* Start von 03_/auth/session&lt;br /&gt;
   7. get PV_Anlage_1_API 03_/auth/session&lt;br /&gt;
* /api/v1/auth/session - HTTP request erfolgt&lt;br /&gt;
* auth_sessionId wird empfangen&lt;br /&gt;
&lt;br /&gt;
Bei allen folgenden HTTP requests wird nun die erhaltene auth_sessenId übermittelt.&lt;br /&gt;
&lt;br /&gt;
Bereits Implementierte Abfragen:&lt;br /&gt;
&lt;br /&gt;
get:&lt;br /&gt;
&lt;br /&gt;
start, finish, create_session werden für den Login benötigt und arbeiten über userreadings mit zwei Python Skripten zusammen&lt;br /&gt;
&lt;br /&gt;
01_/auth/start&lt;br /&gt;
&lt;br /&gt;
02_/auth/finish&lt;br /&gt;
&lt;br /&gt;
03_/auth/create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand, es muss aber kurz vorher abgefragt werden&lt;br /&gt;
&lt;br /&gt;
04_/auth/me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
&lt;br /&gt;
05_/info/version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
&lt;br /&gt;
20_/processdata/scb_statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit attr &amp;lt;Device&amp;gt; showBody 1 angezeigt werden kann.&lt;br /&gt;
&lt;br /&gt;
21_/modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
&lt;br /&gt;
24_/logdata/download&lt;br /&gt;
&lt;br /&gt;
Speicher Typen wurden folgende ermittelt 0=keine , 4=BYD&lt;br /&gt;
&lt;br /&gt;
Diese Abfragewerte können auch gesetzt werden, siehe set Befehle&lt;br /&gt;
&lt;br /&gt;
31_Battery_Type&lt;br /&gt;
&lt;br /&gt;
32_Battery_MinHomeComsumption&lt;br /&gt;
&lt;br /&gt;
33_Battery_Strategy&lt;br /&gt;
&lt;br /&gt;
34_Battery_MinSoc&lt;br /&gt;
&lt;br /&gt;
35_Battery_SmartBatteryControl_Enable&lt;br /&gt;
&lt;br /&gt;
36_Battery_DynamicSoc_Enable&lt;br /&gt;
&lt;br /&gt;
Das zeigt den FW Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
&lt;br /&gt;
41_/update/status&lt;br /&gt;
&lt;br /&gt;
set:&lt;br /&gt;
&lt;br /&gt;
Eine bestehende Session wird abgemeldet&lt;br /&gt;
&lt;br /&gt;
06_/auth/logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
&lt;br /&gt;
23_/events/latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
&lt;br /&gt;
31_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
32_Battery_MinHomeComsumption&lt;br /&gt;
&lt;br /&gt;
33_Battery_Strategy&lt;br /&gt;
&lt;br /&gt;
34_Battery_MinSoc&lt;br /&gt;
&lt;br /&gt;
35_Battery_SmartBatteryControl_Enable&lt;br /&gt;
&lt;br /&gt;
36_Battery_DynamicSoc_Enable&lt;br /&gt;
&lt;br /&gt;
Der Reboot läuft noch nicht. Da ist die API ziemlich zickig. Ich habe jedoch bereits ein Skript, womit es geht :-)&lt;br /&gt;
&lt;br /&gt;
51_/system/reboot&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch eine Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
====== RAW Definition des PV_Anlage_1_API ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Anlage_1_API HTTPMOD http://%IP-Address_Plenticore%/api/v1/auth/me 0&lt;br /&gt;
&lt;br /&gt;
attr PV_Anlage_1_API DbLogExclude .*&lt;br /&gt;
attr PV_Anlage_1_API DbLogInclude Statistic_.*&lt;br /&gt;
attr PV_Anlage_1_API authRetries 1&lt;br /&gt;
attr PV_Anlage_1_API dontRequeueAfterAuth 1&lt;br /&gt;
attr PV_Anlage_1_API enableControlSet 0&lt;br /&gt;
attr PV_Anlage_1_API enableCookies 1&lt;br /&gt;
attr PV_Anlage_1_API get01Data {&amp;quot;nonce&amp;quot;: &amp;quot;%randomString64%&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API get01Name 01_/auth/start&lt;br /&gt;
attr PV_Anlage_1_API get01URL http://%IP-Address_Plenticore%/api/v1/auth/start&lt;br /&gt;
attr PV_Anlage_1_API get02-1Name auth_signature&lt;br /&gt;
attr PV_Anlage_1_API get02-2Name auth_token&lt;br /&gt;
attr PV_Anlage_1_API get02Data {&amp;quot;transactionId&amp;quot;: &amp;quot;%auth_transactionId%&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;%auth_proof%&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API get02JSON .&lt;br /&gt;
attr PV_Anlage_1_API get02Name 02_/auth/finish&lt;br /&gt;
attr PV_Anlage_1_API get02URL http://%IP-Address_Plenticore%/api/v1/auth/finish&lt;br /&gt;
attr PV_Anlage_1_API get03Data {&amp;quot;transactionId&amp;quot;: &amp;quot;%auth_transactionId%&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;%auth_iv%&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;%auth_authtag%&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;%auth_payload%&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API get03Name 03_/auth/create_session&lt;br /&gt;
attr PV_Anlage_1_API get03URL http://%IP-Address_Plenticore%/api/v1/auth/create_session&lt;br /&gt;
attr PV_Anlage_1_API get04-1Name auth_me_active&lt;br /&gt;
attr PV_Anlage_1_API get04-2Name auth_me_locked&lt;br /&gt;
attr PV_Anlage_1_API get04-3Name auth_me_authenticated&lt;br /&gt;
attr PV_Anlage_1_API get04-4Name auth_me_anonymous&lt;br /&gt;
attr PV_Anlage_1_API get04-5Name auth_me_role&lt;br /&gt;
attr PV_Anlage_1_API get04-6Name auth_me_permissions&lt;br /&gt;
attr PV_Anlage_1_API get04Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get04JSON .&lt;br /&gt;
attr PV_Anlage_1_API get04Name 04_/auth/me&lt;br /&gt;
attr PV_Anlage_1_API get04URL http://%IP-Address_Plenticore%/api/v1/auth/me&lt;br /&gt;
attr PV_Anlage_1_API get05-1Name info_name&lt;br /&gt;
attr PV_Anlage_1_API get05-2Name info_api_version&lt;br /&gt;
attr PV_Anlage_1_API get05-3Name info_sw_version&lt;br /&gt;
attr PV_Anlage_1_API get05-4Name info_hostname&lt;br /&gt;
attr PV_Anlage_1_API get05JSON .&lt;br /&gt;
attr PV_Anlage_1_API get05Name 05_/info/version&lt;br /&gt;
attr PV_Anlage_1_API get05URL http://%IP-Address_Plenticore%/api/v1/info/version&lt;br /&gt;
attr PV_Anlage_1_API get20-10Name Statistic_EnergyHome_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-11Name Statistic_EnergyHome_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-12Name Statistic_EnergyHome_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-13Name Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-14Name Statistic_EnergyHomeBat_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-15Name Statistic_EnergyHomeBat_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-16Name Statistic_EnergyHomeBat_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-17Name Statistic_EnergyHomeGrid_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-18Name Statistic_EnergyHomeGrid_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-19Name Statistic_EnergyHomeGrid_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-1Name Statistic_Autarky_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-20Name Statistic_EnergyHomeGrid_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-21Name Statistic_EnergyHomePv_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-22Name Statistic_EnergyHomePv_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-23Name Statistic_EnergyHomePv_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-24Name Statistic_EnergyHomePv_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-25Name Statistic_OwnConsumptionRate_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-26Name Statistic_OwnConsumptionRate_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-27Name Statistic_OwnConsumptionRate_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-28Name Statistic_OwnConsumptionRate_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-29Name Statistic_Yield_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-2Name Statistic_Autarky_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-30Name Statistic_Yield_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-31Name Statistic_Yield_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-32Name Statistic_Yield_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-3Name Statistic_Autarky_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-4Name Statistic_Autarky_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-5Name Statistic_CO2Saving_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-6Name Statistic_CO2Saving_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-7Name Statistic_CO2Saving_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-8Name Statistic_CO2Saving_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-9Name Statistic_EnergyHome_Day&lt;br /&gt;
attr PV_Anlage_1_API get20Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get20JSON 01_processdata_.._value&lt;br /&gt;
attr PV_Anlage_1_API get20Name 20_/processdata/scb_statistic_EnergyFlow&lt;br /&gt;
attr PV_Anlage_1_API get20URL http://%IP-Address_Plenticore%/api/v1/processdata/scb:statistic:EnergyFlow&lt;br /&gt;
attr PV_Anlage_1_API get21Name 21_/modules_list&lt;br /&gt;
attr PV_Anlage_1_API get21URL http://%IP-Address_Plenticore%/api/v1/modules&lt;br /&gt;
attr PV_Anlage_1_API get24Data {&amp;quot;end&amp;quot;:&amp;quot;%end_date%&amp;quot;,&amp;quot;begin&amp;quot;:&amp;quot;%begin_date%&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API get24Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get24Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get24Name 24_/logdata/download&lt;br /&gt;
attr PV_Anlage_1_API get24URL http://%IP-Address_Plenticore%/api/v1/logdata/download&lt;br /&gt;
attr PV_Anlage_1_API get31-1Name Battery_Type&lt;br /&gt;
attr PV_Anlage_1_API get31-2Name Battery_Type&lt;br /&gt;
attr PV_Anlage_1_API get31Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get31Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get31JSON .&lt;br /&gt;
attr PV_Anlage_1_API get31Name 31_Battery_Type&lt;br /&gt;
attr PV_Anlage_1_API get31URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:Type&lt;br /&gt;
attr PV_Anlage_1_API get32-1Name Battery_MinHomeComsumption&lt;br /&gt;
attr PV_Anlage_1_API get32-2Name Battery_MinHomeComsumption&lt;br /&gt;
attr PV_Anlage_1_API get32Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get32Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get32JSON .&lt;br /&gt;
attr PV_Anlage_1_API get32Name 32_Battery_MinHomeComsumption&lt;br /&gt;
attr PV_Anlage_1_API get32URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:MinHomeComsumption&lt;br /&gt;
attr PV_Anlage_1_API get33-1Name Battery_Strategy&lt;br /&gt;
attr PV_Anlage_1_API get33-2Name Battery_Strategy&lt;br /&gt;
attr PV_Anlage_1_API get33Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get33Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get33JSON .&lt;br /&gt;
attr PV_Anlage_1_API get33Name 33_Battery_Strategy&lt;br /&gt;
attr PV_Anlage_1_API get33URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:Strategy&lt;br /&gt;
attr PV_Anlage_1_API get34-1Name Battery_MinSoc&lt;br /&gt;
attr PV_Anlage_1_API get34-2Name Battery_MinSoc&lt;br /&gt;
attr PV_Anlage_1_API get34Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get34Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get34JSON .&lt;br /&gt;
attr PV_Anlage_1_API get34Name 34_Battery_MinSoc&lt;br /&gt;
attr PV_Anlage_1_API get34URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:MinSoc&lt;br /&gt;
attr PV_Anlage_1_API get35-1Name Battery_SmartBatteryControl_Enable&lt;br /&gt;
attr PV_Anlage_1_API get35-2Name Battery_SmartBatteryControl_Enable&lt;br /&gt;
attr PV_Anlage_1_API get35Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get35Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get35JSON .&lt;br /&gt;
attr PV_Anlage_1_API get35Name 35_Battery_SmartBatteryControl_Enable&lt;br /&gt;
attr PV_Anlage_1_API get35URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:SmartBatteryControl:Enable&lt;br /&gt;
attr PV_Anlage_1_API get36-1Name Battery_DynamicSoc_Enable&lt;br /&gt;
attr PV_Anlage_1_API get36-2Name Battery_DynamicSoc_Enable&lt;br /&gt;
attr PV_Anlage_1_API get36Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get36Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get36JSON .&lt;br /&gt;
attr PV_Anlage_1_API get36Name 36_Battery_DynamicSoc_Enable&lt;br /&gt;
attr PV_Anlage_1_API get36URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:DynamicSoc:Enable&lt;br /&gt;
attr PV_Anlage_1_API get41Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get41Name 41_/update/status&lt;br /&gt;
attr PV_Anlage_1_API get41URL http://%IP-Address_Plenticore%/api/v1/update/status&lt;br /&gt;
attr PV_Anlage_1_API getHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr PV_Anlage_1_API getHeader02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API group PV Eigenverbrauch&lt;br /&gt;
attr PV_Anlage_1_API icon sani_solar&lt;br /&gt;
attr PV_Anlage_1_API reAuthRegex &amp;quot;authenticated&amp;quot;:false|&amp;quot;processdata&amp;quot;:\[\]|wrong credentials&lt;br /&gt;
attr PV_Anlage_1_API reading01-1Name auth_nonce&lt;br /&gt;
attr PV_Anlage_1_API reading01-2Name auth_rounds&lt;br /&gt;
attr PV_Anlage_1_API reading01-3Name auth_salt&lt;br /&gt;
attr PV_Anlage_1_API reading01-4Name auth_transactionId&lt;br /&gt;
attr PV_Anlage_1_API reading01JSON .&lt;br /&gt;
attr PV_Anlage_1_API reading02JSON sessionId&lt;br /&gt;
attr PV_Anlage_1_API reading02Name auth_sessionId&lt;br /&gt;
attr PV_Anlage_1_API reading0301JSON message&lt;br /&gt;
attr PV_Anlage_1_API reading0301Name info_message&lt;br /&gt;
attr PV_Anlage_1_API reading0302JSON error&lt;br /&gt;
attr PV_Anlage_1_API reading0302Name info_error&lt;br /&gt;
attr PV_Anlage_1_API replacement01Mode expression&lt;br /&gt;
attr PV_Anlage_1_API replacement01Regex %IP-Address_Plenticore%&lt;br /&gt;
attr PV_Anlage_1_API replacement01Value {ReadingsVal(&amp;quot;PV_Anlage_1_config&amp;quot;,&amp;quot;IP-Address_Plenticore&amp;quot;,&amp;quot;&amp;quot;)}&lt;br /&gt;
attr PV_Anlage_1_API replacement02Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement02Regex %auth_transactionId%&lt;br /&gt;
attr PV_Anlage_1_API replacement02Value auth_transactionId&lt;br /&gt;
attr PV_Anlage_1_API replacement03Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement03Regex %auth_proof%&lt;br /&gt;
attr PV_Anlage_1_API replacement03Value auth_proof&lt;br /&gt;
attr PV_Anlage_1_API replacement04Mode expression&lt;br /&gt;
attr PV_Anlage_1_API replacement04Regex %randomString64%&lt;br /&gt;
attr PV_Anlage_1_API replacement04Value {my $NAME = &amp;quot;PV_Anlage_1_API&amp;quot; ;;;;fhem(&amp;quot;deletereading &amp;quot;.$NAME.&amp;quot; message&amp;quot;);;;;fhem(&amp;quot;deletereading &amp;quot;.$NAME.&amp;quot; auth.*&amp;quot;);;;;my @chars=(&#039;a&#039;..&#039;z&#039;,&#039;A&#039;..&#039;Z&#039;,&#039;0&#039;..&#039;9&#039;);; my $r;; foreach(1..16) {$r.=$chars[rand @chars];;};;;; fhem(&amp;quot;setreading &amp;quot;.$NAME.&amp;quot; auth_randomString64 &amp;quot;.$r);;;; $r;;;;}&lt;br /&gt;
attr PV_Anlage_1_API replacement05Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement05Regex %auth_randomString64%&lt;br /&gt;
attr PV_Anlage_1_API replacement05Value auth_randomString64&lt;br /&gt;
attr PV_Anlage_1_API replacement06Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement06Regex %auth_token%&lt;br /&gt;
attr PV_Anlage_1_API replacement06Value auth_token&lt;br /&gt;
attr PV_Anlage_1_API replacement07Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement07Regex %auth_signature%&lt;br /&gt;
attr PV_Anlage_1_API replacement07Value auth_signature&lt;br /&gt;
attr PV_Anlage_1_API replacement08Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement08Regex %auth_authtag%&lt;br /&gt;
attr PV_Anlage_1_API replacement08Value auth_authtag&lt;br /&gt;
attr PV_Anlage_1_API replacement09Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement09Regex %auth_payload%&lt;br /&gt;
attr PV_Anlage_1_API replacement09Value auth_payload&lt;br /&gt;
attr PV_Anlage_1_API replacement10Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement10Regex %auth_iv%&lt;br /&gt;
attr PV_Anlage_1_API replacement10Value auth_iv&lt;br /&gt;
attr PV_Anlage_1_API replacement11Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement11Regex %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API replacement11Value auth_sessionId&lt;br /&gt;
attr PV_Anlage_1_API replacement12Mode expression&lt;br /&gt;
attr PV_Anlage_1_API replacement12Regex %begin_date%&lt;br /&gt;
attr PV_Anlage_1_API replacement12Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr PV_Anlage_1_API replacement13Mode expression&lt;br /&gt;
attr PV_Anlage_1_API replacement13Regex %end_date%&lt;br /&gt;
attr PV_Anlage_1_API replacement13Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr PV_Anlage_1_API room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Anlage_1_API set06Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set06Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set06Method POST&lt;br /&gt;
attr PV_Anlage_1_API set06Name 06_/auth/logout&lt;br /&gt;
attr PV_Anlage_1_API set06NoArg 1&lt;br /&gt;
attr PV_Anlage_1_API set06URL http://%IP-Address_Plenticore%/api/v1/auth/logout&lt;br /&gt;
attr PV_Anlage_1_API set23-10Name Event_02_code&lt;br /&gt;
attr PV_Anlage_1_API set23-11Name Event_02_description&lt;br /&gt;
attr PV_Anlage_1_API set23-12Name Event_02_end_time&lt;br /&gt;
attr PV_Anlage_1_API set23-13Name Event_02_group&lt;br /&gt;
attr PV_Anlage_1_API set23-14Name Event_02_is_active&lt;br /&gt;
attr PV_Anlage_1_API set23-15Name Event_02_long_description&lt;br /&gt;
attr PV_Anlage_1_API set23-16Name Event_02_start_time&lt;br /&gt;
attr PV_Anlage_1_API set23-17Name Event_03_category&lt;br /&gt;
attr PV_Anlage_1_API set23-18Name Event_03_code&lt;br /&gt;
attr PV_Anlage_1_API set23-19Name Event_03_description&lt;br /&gt;
attr PV_Anlage_1_API set23-1Name Event_01_category&lt;br /&gt;
attr PV_Anlage_1_API set23-20Name Event_03_end_time&lt;br /&gt;
attr PV_Anlage_1_API set23-21Name Event_03_group&lt;br /&gt;
attr PV_Anlage_1_API set23-22Name Event_03_is_active&lt;br /&gt;
attr PV_Anlage_1_API set23-23Name Event_03_long_description&lt;br /&gt;
attr PV_Anlage_1_API set23-24Name Event_03_start_time&lt;br /&gt;
attr PV_Anlage_1_API set23-25Name Event_04_category&lt;br /&gt;
attr PV_Anlage_1_API set23-26Name Event_04_code&lt;br /&gt;
attr PV_Anlage_1_API set23-27Name Event_04_description&lt;br /&gt;
attr PV_Anlage_1_API set23-28Name Event_04_end_time&lt;br /&gt;
attr PV_Anlage_1_API set23-29Name Event_04_group&lt;br /&gt;
attr PV_Anlage_1_API set23-2Name Event_01_code&lt;br /&gt;
attr PV_Anlage_1_API set23-30Name Event_04_is_active&lt;br /&gt;
attr PV_Anlage_1_API set23-31Name Event_04_long_description&lt;br /&gt;
attr PV_Anlage_1_API set23-32Name Event_04_start_time&lt;br /&gt;
attr PV_Anlage_1_API set23-33Name Event_05_category&lt;br /&gt;
attr PV_Anlage_1_API set23-34Name Event_05_code&lt;br /&gt;
attr PV_Anlage_1_API set23-35Name Event_05_description&lt;br /&gt;
attr PV_Anlage_1_API set23-36Name Event_05_end_time&lt;br /&gt;
attr PV_Anlage_1_API set23-37Name Event_05_group&lt;br /&gt;
attr PV_Anlage_1_API set23-38Name Event_05_is_active&lt;br /&gt;
attr PV_Anlage_1_API set23-39Name Event_05_long_description&lt;br /&gt;
attr PV_Anlage_1_API set23-3Name Event_01_description&lt;br /&gt;
attr PV_Anlage_1_API set23-40Name Event_05_start_time&lt;br /&gt;
attr PV_Anlage_1_API set23-4Name Event_01_end_time&lt;br /&gt;
attr PV_Anlage_1_API set23-5Name Event_01_group&lt;br /&gt;
attr PV_Anlage_1_API set23-6Name Event_01_is_active&lt;br /&gt;
attr PV_Anlage_1_API set23-7Name Event_01_long_description&lt;br /&gt;
attr PV_Anlage_1_API set23-8Name Event_01_start_time&lt;br /&gt;
attr PV_Anlage_1_API set23-9Name Event_02_category&lt;br /&gt;
attr PV_Anlage_1_API set23Data {&amp;quot;max&amp;quot;:5,&amp;quot;language&amp;quot;:&amp;quot;$val&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API set23Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set23Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set23Hint en-gb,de-de&lt;br /&gt;
attr PV_Anlage_1_API set23JSON .&lt;br /&gt;
attr PV_Anlage_1_API set23Name 23_/events/latest_5&lt;br /&gt;
attr PV_Anlage_1_API set23ParseResponse 1&lt;br /&gt;
attr PV_Anlage_1_API set23TextArg 1&lt;br /&gt;
attr PV_Anlage_1_API set23URL http://%IP-Address_Plenticore%/api/v1/events/latest&lt;br /&gt;
attr PV_Anlage_1_API set31Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:Type&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr PV_Anlage_1_API set31Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set31Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set31Hint 0,4&lt;br /&gt;
attr PV_Anlage_1_API set31Method PUT&lt;br /&gt;
attr PV_Anlage_1_API set31Name 31_Battery_Type&lt;br /&gt;
attr PV_Anlage_1_API set31URL http://%IP-Address_Plenticore%/api/v1/settings&lt;br /&gt;
attr PV_Anlage_1_API set33Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:Strategy&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr PV_Anlage_1_API set33Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set33Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set33Hint 1,2&lt;br /&gt;
attr PV_Anlage_1_API set33Method PUT&lt;br /&gt;
attr PV_Anlage_1_API set33Name 31_Battery_Strategy&lt;br /&gt;
attr PV_Anlage_1_API set33URL http://%IP-Address_Plenticore%/api/v1/settings&lt;br /&gt;
attr PV_Anlage_1_API set34Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:MinSoc&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr PV_Anlage_1_API set34Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set34Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set34Hint slider,10,5,100&lt;br /&gt;
attr PV_Anlage_1_API set34Method PUT&lt;br /&gt;
attr PV_Anlage_1_API set34Name 34_Battery_MinSoc&lt;br /&gt;
attr PV_Anlage_1_API set34URL http://%IP-Address_Plenticore%/api/v1/settings&lt;br /&gt;
attr PV_Anlage_1_API set35Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:SmartBatteryControl:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr PV_Anlage_1_API set35Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set35Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set35Hint 0,1&lt;br /&gt;
attr PV_Anlage_1_API set35Method PUT&lt;br /&gt;
attr PV_Anlage_1_API set35Name 35_SmartBatteryControl_Enable&lt;br /&gt;
attr PV_Anlage_1_API set35URL http://%IP-Address_Plenticore%/api/v1/settings&lt;br /&gt;
attr PV_Anlage_1_API set51Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set51Header02 Accept: application/json, Connection: keep-alive, Content-type: application/json&lt;br /&gt;
attr PV_Anlage_1_API set51Method Post&lt;br /&gt;
attr PV_Anlage_1_API set51Name 51_/system/reboot&lt;br /&gt;
attr PV_Anlage_1_API set51NoArg 1&lt;br /&gt;
attr PV_Anlage_1_API set51URL http://%IP-Address_Plenticore%/api/v1/system/reboot&lt;br /&gt;
attr PV_Anlage_1_API showBody 1&lt;br /&gt;
attr PV_Anlage_1_API showError 1&lt;br /&gt;
attr PV_Anlage_1_API sid01Data {&amp;quot;nonce&amp;quot;: &amp;quot;%randomString64%&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API sid01ParseResponse 1&lt;br /&gt;
attr PV_Anlage_1_API sid01URL http://%IP-Address_Plenticore%/api/v1/auth/start&lt;br /&gt;
attr PV_Anlage_1_API sidHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr PV_Anlage_1_API sidHeader02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr PV_Anlage_1_API sortby 02&lt;br /&gt;
attr PV_Anlage_1_API timeout 7&lt;br /&gt;
attr PV_Anlage_1_API userReadings auth_first_called:auth_randomString64.* {my $first_called = InternalVal(&amp;quot;$NAME&amp;quot;,&amp;quot;path&amp;quot;,&amp;quot;n.a&amp;quot;);;;; $first_called =~ s/:/_/g;;;;$first_called ;;;;$first_called =~ s/\/api\/v1//g;;;; my %replace = (&amp;quot;/auth/me&amp;quot; =&amp;gt; &amp;quot;04_/auth/me&amp;quot;,&amp;quot;/info/version&amp;quot; =&amp;gt; &amp;quot;05_/info/version&amp;quot;,&amp;quot;/processdata/scb_statistic_EnergyFlow&amp;quot; =&amp;gt; &amp;quot;20_/processdata/scb_statistic_EnergyFlow&amp;quot;,&amp;quot;/modules_list&amp;quot; =&amp;gt; &amp;quot;21_/modules_list&amp;quot;,&amp;quot;/logdata/download&amp;quot; =&amp;gt; &amp;quot;24_/logdata/download&amp;quot;,&amp;quot;/update/status&amp;quot; =&amp;gt; &amp;quot;41_/update/status&amp;quot;,&amp;quot;/system/reboot&amp;quot; =&amp;gt; &amp;quot;04_/auth/me&amp;quot;,);;;; $replace{$first_called};;;;},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step1_Message:auth_transactionId.* {system(&amp;quot;/usr/bin/python3 /opt/fhem/python/bin/plenticore_auth_finish.py &amp;quot;.ReadingsVal(&amp;quot;PV_Anlage_1_config&amp;quot;,&amp;quot;IP-Address_FHEM&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;29000&amp;quot;).&amp;quot; &amp;amp;&amp;quot;);;;; &amp;quot;Prepare auth_finish started with auth_nonce &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;)},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step2_Message:auth_proof.* { fhem(&amp;quot;get &amp;quot;.$NAME.&amp;quot; 02_/auth/finish&amp;quot;) ;;;; &amp;quot;HTTP Request 02_/auth/finish with auth_proof &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_proof&amp;quot;,&amp;quot;&amp;quot;)},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step3_Message:auth_token.* {system(&amp;quot;/usr/bin/python3 /opt/fhem/python/bin/plenticore_auth_session.py &amp;quot;.ReadingsVal(&amp;quot;PV_Anlage_1_config&amp;quot;,&amp;quot;IP-Address_FHEM&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;amp;&amp;quot;);;;; &amp;quot;Prepare auth_session started with auth_token &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;&amp;quot;)},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step4_Message:auth_payload.* { fhem(&amp;quot;get &amp;quot;.$NAME.&amp;quot; 03_/auth/create_session&amp;quot;) ;;;; &amp;quot;HTTP Request 03_/auth/create_session with auth_authtag &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_authtag&amp;quot;,&amp;quot;&amp;quot;)},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step5_Message:auth_sessionId.* {my $restack = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_first_called&amp;quot;,&amp;quot;&amp;quot;) ;;;; ($restack != &amp;quot;&amp;quot;)?fhem(&amp;quot;get &amp;quot;.$NAME.&amp;quot; &amp;quot;.$restack):&amp;quot;No further HTTP request&amp;quot;;;;;}&lt;br /&gt;
attr PV_Anlage_1_API verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kostal Smart Energy Manager (KSEM) (Modbus/TCP) ===&lt;br /&gt;
Diese Einbindung ist nicht zwingend notwendig, jedoch weil es möglich ist hier beschrieben.&lt;br /&gt;
Das Gerät ist hier mit &amp;quot;disable 1&amp;quot; konfiguriert, um es zu verwenden muss das Attribut auf 0 gesetzt oder einfach gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist noch komplett deaktiviert, weshalb man seine Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_KSEM ModbusAttr 1 60 &amp;lt;IP-Address_KSEM&amp;gt;:502 TCP&lt;br /&gt;
attr PV_KSEM DbLogExclude .*&lt;br /&gt;
attr PV_KSEM alias PV_Energy_Manager&lt;br /&gt;
attr PV_KSEM dev-h-defPoll 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Current-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Current_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Current-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Current-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Current-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Freq-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Freq_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Freq-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Freq-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Freq-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_PF-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_PF_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_PF-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_PF-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_PF-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Power-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Power_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Power-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Power-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Power-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VA-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VA_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VA-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VA-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VA-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VAR-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VAR_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VAR-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VAR-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VAR-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Voltage-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Voltage_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Voltage-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Voltage-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Voltage-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-STR32-expr $val =~ s/[\00]+//gr&lt;br /&gt;
attr PV_KSEM dev-type-STR32-format %s&lt;br /&gt;
attr PV_KSEM dev-type-STR32-len 16&lt;br /&gt;
attr PV_KSEM dev-type-STR32-unpack a*&lt;br /&gt;
attr PV_KSEM dev-type-UINT16-format %s&lt;br /&gt;
attr PV_KSEM dev-type-UINT16-len 1&lt;br /&gt;
attr PV_KSEM dev-type-UINT32-format %s&lt;br /&gt;
attr PV_KSEM dev-type-UINT32-len 2&lt;br /&gt;
attr PV_KSEM dev-type-UINT64-expr $val/10000&lt;br /&gt;
attr PV_KSEM dev-type-UINT64-format %s&lt;br /&gt;
attr PV_KSEM dev-type-UINT64-len 4&lt;br /&gt;
attr PV_KSEM dev-type-UINT64-unpack Q&amp;gt;&lt;br /&gt;
attr PV_KSEM disable 1&lt;br /&gt;
attr PV_KSEM group PV Eigenverbrauch&lt;br /&gt;
attr PV_KSEM icon measure_power&lt;br /&gt;
attr PV_KSEM obj-h40072-reading M_AC_Current_A&lt;br /&gt;
attr PV_KSEM obj-h40072-type INT16_Current&lt;br /&gt;
attr PV_KSEM obj-h40073-reading M_AC_Current_B&lt;br /&gt;
attr PV_KSEM obj-h40073-type INT16_Current&lt;br /&gt;
attr PV_KSEM obj-h40074-reading M_AC_Current_C&lt;br /&gt;
attr PV_KSEM obj-h40074-type INT16_Current&lt;br /&gt;
attr PV_KSEM obj-h40075-reading M_AC_Current_SF&lt;br /&gt;
attr PV_KSEM obj-h40075-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40077-reading M_AC_Voltage_AN&lt;br /&gt;
attr PV_KSEM obj-h40077-type INT16_Voltage&lt;br /&gt;
attr PV_KSEM obj-h40078-reading M_AC_Voltage_BN&lt;br /&gt;
attr PV_KSEM obj-h40078-type INT16_Voltage&lt;br /&gt;
attr PV_KSEM obj-h40079-reading M_AC_Voltage_CN&lt;br /&gt;
attr PV_KSEM obj-h40079-type INT16_Voltage&lt;br /&gt;
attr PV_KSEM obj-h40084-reading M_AC_Voltage_SF&lt;br /&gt;
attr PV_KSEM obj-h40084-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40085-reading M_AC_Freq&lt;br /&gt;
attr PV_KSEM obj-h40085-type INT16_Freq&lt;br /&gt;
attr PV_KSEM obj-h40086-reading M_AC_Freq_SF&lt;br /&gt;
attr PV_KSEM obj-h40086-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40087-reading M_AC_Power&lt;br /&gt;
attr PV_KSEM obj-h40087-type INT16_Power&lt;br /&gt;
attr PV_KSEM obj-h40088-reading M_AC_Power_A&lt;br /&gt;
attr PV_KSEM obj-h40088-type INT16_Power&lt;br /&gt;
attr PV_KSEM obj-h40089-reading M_AC_Power_B&lt;br /&gt;
attr PV_KSEM obj-h40089-type INT16_Power&lt;br /&gt;
attr PV_KSEM obj-h40090-reading M_AC_Power_C&lt;br /&gt;
attr PV_KSEM obj-h40090-type INT16_Power&lt;br /&gt;
attr PV_KSEM obj-h40091-reading M_AC_Power_SF&lt;br /&gt;
attr PV_KSEM obj-h40091-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40092-reading M_AC_VA&lt;br /&gt;
attr PV_KSEM obj-h40092-type INT16_VA&lt;br /&gt;
attr PV_KSEM obj-h40093-reading M_AC_VA_A&lt;br /&gt;
attr PV_KSEM obj-h40093-type INT16_VA&lt;br /&gt;
attr PV_KSEM obj-h40094-reading M_AC_VA_B&lt;br /&gt;
attr PV_KSEM obj-h40094-type INT16_VA&lt;br /&gt;
attr PV_KSEM obj-h40095-reading M_AC_VA_C&lt;br /&gt;
attr PV_KSEM obj-h40095-type INT16_VA&lt;br /&gt;
attr PV_KSEM obj-h40096-reading M_AC_VA_SF&lt;br /&gt;
attr PV_KSEM obj-h40096-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40097-reading M_AC_VAR&lt;br /&gt;
attr PV_KSEM obj-h40097-type INT16_VAR&lt;br /&gt;
attr PV_KSEM obj-h40098-reading M_AC_VAR_A&lt;br /&gt;
attr PV_KSEM obj-h40098-type INT16_VAR&lt;br /&gt;
attr PV_KSEM obj-h40099-reading M_AC_VAR_B&lt;br /&gt;
attr PV_KSEM obj-h40099-type INT16_VAR&lt;br /&gt;
attr PV_KSEM obj-h40100-reading M_AC_VAR_C&lt;br /&gt;
attr PV_KSEM obj-h40100-type INT16_VAR&lt;br /&gt;
attr PV_KSEM obj-h40101-reading M_AC_VAR_SF&lt;br /&gt;
attr PV_KSEM obj-h40101-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40102-reading M_AC_PF&lt;br /&gt;
attr PV_KSEM obj-h40102-type INT16_PF&lt;br /&gt;
attr PV_KSEM obj-h40103-reading M_AC_PF_A&lt;br /&gt;
attr PV_KSEM obj-h40103-type INT16_PF&lt;br /&gt;
attr PV_KSEM obj-h40104-reading M_AC_PF_B&lt;br /&gt;
attr PV_KSEM obj-h40104-type INT16_PF&lt;br /&gt;
attr PV_KSEM obj-h40105-reading M_AC_PF_C&lt;br /&gt;
attr PV_KSEM obj-h40105-type INT16_PF&lt;br /&gt;
attr PV_KSEM obj-h40106-reading M_AC_PF_SF&lt;br /&gt;
attr PV_KSEM obj-h40106-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40108-reading M_Exported&lt;br /&gt;
attr PV_KSEM obj-h40108-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40110-reading M_Exported_A&lt;br /&gt;
attr PV_KSEM obj-h40110-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40112-reading M_Exported_B&lt;br /&gt;
attr PV_KSEM obj-h40112-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40114-reading M_Exported_C&lt;br /&gt;
attr PV_KSEM obj-h40114-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40116-reading M_Imported&lt;br /&gt;
attr PV_KSEM obj-h40116-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40118-reading M_Imported_A&lt;br /&gt;
attr PV_KSEM obj-h40118-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40120-reading M_Imported_B&lt;br /&gt;
attr PV_KSEM obj-h40120-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40122-reading M_Imported_C&lt;br /&gt;
attr PV_KSEM obj-h40122-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40125-reading M_Exported_VA&lt;br /&gt;
attr PV_KSEM obj-h40125-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40127-reading M_Exported_VA_A&lt;br /&gt;
attr PV_KSEM obj-h40127-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40129-reading M_Exported_VA_B&lt;br /&gt;
attr PV_KSEM obj-h40129-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40131-reading M_Exported_VA_C&lt;br /&gt;
attr PV_KSEM obj-h40131-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40133-reading M_Imported_VA&lt;br /&gt;
attr PV_KSEM obj-h40133-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40135-reading M_Imported_VA_A&lt;br /&gt;
attr PV_KSEM obj-h40135-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40137-reading M_Imported_VA_B&lt;br /&gt;
attr PV_KSEM obj-h40137-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40139-reading M_Imported_VA_C&lt;br /&gt;
attr PV_KSEM obj-h40139-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h512-reading Active_energy+&lt;br /&gt;
attr PV_KSEM obj-h512-type UINT64&lt;br /&gt;
attr PV_KSEM obj-h516-reading Active_energy-&lt;br /&gt;
attr PV_KSEM obj-h516-type UINT64&lt;br /&gt;
attr PV_KSEM obj-h8192-reading ManufacturerID&lt;br /&gt;
attr PV_KSEM obj-h8192-type UINT16&lt;br /&gt;
attr PV_KSEM obj-h8193-reading ProductID&lt;br /&gt;
attr PV_KSEM obj-h8193-type UINT16&lt;br /&gt;
attr PV_KSEM obj-h8194-reading ProductVersion&lt;br /&gt;
attr PV_KSEM obj-h8194-type UINT16&lt;br /&gt;
attr PV_KSEM obj-h8195-reading FirmwareVersion&lt;br /&gt;
attr PV_KSEM obj-h8195-type UINT16&lt;br /&gt;
attr PV_KSEM obj-h8196-reading VendorName&lt;br /&gt;
attr PV_KSEM obj-h8196-type STR32&lt;br /&gt;
attr PV_KSEM obj-h8212-reading Productname&lt;br /&gt;
attr PV_KSEM obj-h8212-type STR32&lt;br /&gt;
attr PV_KSEM obj-h8228-reading SerialNumber&lt;br /&gt;
attr PV_KSEM obj-h8228-type STR32&lt;br /&gt;
attr PV_KSEM obj-h8244-reading MeasuringInterval&lt;br /&gt;
attr PV_KSEM obj-h8244-type UINT16&lt;br /&gt;
attr PV_KSEM room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_KSEM sortby 03&lt;br /&gt;
attr PV_KSEM userReadings M_AC_Current:M_AC_Current_.* { ReadingsVal($NAME,&amp;quot;M_AC_Current_A&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_B&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_C&amp;quot;,0) }&lt;br /&gt;
attr PV_KSEM verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== BYD Speicher (mit HTTPMOD) ===&lt;br /&gt;
Diese Einbindung ist nicht zwingend notwendig.&lt;br /&gt;
Das Passwort steht momentan noch im userreading .&lt;br /&gt;
==== RAW Definition BYD_Status ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod BYD_Status HTTPMOD http://%IP-Address_BYD%/asp/BatteryInformation.asp 0&lt;br /&gt;
&lt;br /&gt;
attr BYD_Status DbLogExclude .*&lt;br /&gt;
attr BYD_Status authRetries 0&lt;br /&gt;
attr BYD_Status devStateIcon 100:measure_battery_100 \d:measure_battery_0 1\d.*:measure_battery_25 2\d.*:measure_battery_25 3\d.*:measure_battery_25 4\d.*:measure_battery_50 5\d.*:measure_battery_50 6\d.*:measure_battery_50 7\d.*:measure_battery_75 8\d.*:measure_battery_75 9\d.*:measure_battery_75&lt;br /&gt;
attr BYD_Status dontRequeueAfterAuth 1&lt;br /&gt;
attr BYD_Status enableControlSet 0&lt;br /&gt;
attr BYD_Status enableCookies 1&lt;br /&gt;
attr BYD_Status get01-101Name Array_Series_Battery_1_CellVol_09&lt;br /&gt;
attr BYD_Status get01-105Name Array_Series_Battery_1_CellVol_10&lt;br /&gt;
attr BYD_Status get01-109Name Array_Series_Battery_1_CellVol_11&lt;br /&gt;
attr BYD_Status get01-113Name Array_Series_Battery_1_CellVol_12&lt;br /&gt;
attr BYD_Status get01-117Name Array_Series_Battery_1_CellVol_13&lt;br /&gt;
attr BYD_Status get01-121Name Array_Series_Battery_1_CellVol_14&lt;br /&gt;
attr BYD_Status get01-125Name Array_Series_Battery_1_CellVol_15&lt;br /&gt;
attr BYD_Status get01-129Name Array_Series_Battery_1_CellVol_16&lt;br /&gt;
attr BYD_Status get01-133Name Array_Series_Battery_1_CellVolMax&lt;br /&gt;
attr BYD_Status get01-137Name Array_Series_Battery_1_CellVolMin&lt;br /&gt;
attr BYD_Status get01-13Name Array_Main_MinCellTemp&lt;br /&gt;
attr BYD_Status get01-141Name Array_Series_Battery_1_CellTemp_1&lt;br /&gt;
attr BYD_Status get01-145Name Array_Series_Battery_1_CellTemp_2&lt;br /&gt;
attr BYD_Status get01-149Name Array_Series_Battery_1_CellTemp_3&lt;br /&gt;
attr BYD_Status get01-14Name Array_Main_SOC&lt;br /&gt;
attr BYD_Status get01-153Name Array_Series_Battery_1_CellTemp_4&lt;br /&gt;
attr BYD_Status get01-17Name Array_Main_SysTemp&lt;br /&gt;
attr BYD_Status get01-1Name Array_Main_ArrayVoltage&lt;br /&gt;
attr BYD_Status get01-21Name Array_Main_MaxCellVol&lt;br /&gt;
attr BYD_Status get01-25Name Array_Main_MinCellVol&lt;br /&gt;
attr BYD_Status get01-29Name Array_Main_MaxCellTemp&lt;br /&gt;
attr BYD_Status get01-33Name Array_Main_MinCellTemp&lt;br /&gt;
attr BYD_Status get01-39Name Array_Main_MaxVolPos&lt;br /&gt;
attr BYD_Status get01-43Name Array_Main_MinVolPos&lt;br /&gt;
attr BYD_Status get01-47Name Array_Main_MaxTempPos&lt;br /&gt;
attr BYD_Status get01-51Name Array_Main_MinTempPos&lt;br /&gt;
attr BYD_Status get01-55Name Array_Main_Power&lt;br /&gt;
attr BYD_Status get01-56Name Array_Series_Battery_1_SerialNumber&lt;br /&gt;
attr BYD_Status get01-5Name Array_Main_PackVoltage&lt;br /&gt;
attr BYD_Status get01-60Name Array_Series_Battery_1_SerialNumber&lt;br /&gt;
attr BYD_Status get01-61Name Array_Series_Battery_1_BattVol&lt;br /&gt;
attr BYD_Status get01-65Name Array_Series_Battery_1_CellVolDiff&lt;br /&gt;
attr BYD_Status get01-69Name Array_Series_Battery_1_CellVol_01&lt;br /&gt;
attr BYD_Status get01-73Name Array_Series_Battery_1_CellVol_02&lt;br /&gt;
attr BYD_Status get01-77Name Array_Series_Battery_1_CellVol_03&lt;br /&gt;
attr BYD_Status get01-81Name Array_Series_Battery_1_CellVol_04&lt;br /&gt;
attr BYD_Status get01-85Name Array_Series_Battery_1_CellVol_05&lt;br /&gt;
attr BYD_Status get01-89Name Array_Series_Battery_1_CellVol_06&lt;br /&gt;
attr BYD_Status get01-93Name Array_Series_Battery_1_CellVol_07&lt;br /&gt;
attr BYD_Status get01-97Name Array_Series_Battery_1_CellVol_08&lt;br /&gt;
attr BYD_Status get01-9Name Array_Main_Current&lt;br /&gt;
attr BYD_Status get01MaxAge 900&lt;br /&gt;
attr BYD_Status get01MaxAgeReplacementMode delete&lt;br /&gt;
attr BYD_Status get01Name RunData&lt;br /&gt;
attr BYD_Status get01RegOpt g&lt;br /&gt;
attr BYD_Status get01Regex value=([+|-]{0,1}\d+.\d+)&amp;gt;|value=(\d+.\d+)%&amp;gt;|value=(\d)&amp;gt;|value=(.*-\d+\s+.*\d)&amp;gt;&lt;br /&gt;
attr BYD_Status get01URL http://%IP-Address_BYD%/asp/RunData.asp&lt;br /&gt;
attr BYD_Status get02-101Name Statistic_SpecificInformation_03_StartTime&lt;br /&gt;
attr BYD_Status get02-105Name Statistic_SpecificInformation_03_EndTime&lt;br /&gt;
attr BYD_Status get02-10Name Statistic_SpecificInformation_02_Type&lt;br /&gt;
attr BYD_Status get02-113Name Statistic_SpecificInformation_04_Type&lt;br /&gt;
attr BYD_Status get02-117Name Statistic_SpecificInformation_04_Ah&lt;br /&gt;
attr BYD_Status get02-11Name Statistic_SpecificInformation_02_Ah&lt;br /&gt;
attr BYD_Status get02-121Name Statistic_SpecificInformation_04_KWh&lt;br /&gt;
attr BYD_Status get02-125Name Statistic_SpecificInformation_04_EnvTemp&lt;br /&gt;
attr BYD_Status get02-129Name Statistic_SpecificInformation_04_BatTemp&lt;br /&gt;
attr BYD_Status get02-12Name Statistic_GeneralInformation_Total_Cycle_Counts&lt;br /&gt;
attr BYD_Status get02-133Name Statistic_SpecificInformation_04_StartTime&lt;br /&gt;
attr BYD_Status get02-137Name Statistic_SpecificInformation_04_EndTime&lt;br /&gt;
attr BYD_Status get02-13Name Statistic_SpecificInformation_02_EnvTemp&lt;br /&gt;
attr BYD_Status get02-145Name Statistic_SpecificInformation_05_Type&lt;br /&gt;
attr BYD_Status get02-149Name Statistic_SpecificInformation_05_Ah&lt;br /&gt;
attr BYD_Status get02-14Name Statistic_SpecificInformation_02_BatTemp&lt;br /&gt;
attr BYD_Status get02-153Name Statistic_SpecificInformation_05_KWh&lt;br /&gt;
attr BYD_Status get02-157Name Statistic_SpecificInformation_05_EnvTemp&lt;br /&gt;
attr BYD_Status get02-15Name Statistic_SpecificInformation_02_StartTime&lt;br /&gt;
attr BYD_Status get02-161Name Statistic_SpecificInformation_05_BatTemp&lt;br /&gt;
attr BYD_Status get02-165Name Statistic_SpecificInformation_05_StartTime&lt;br /&gt;
attr BYD_Status get02-169Name Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr BYD_Status get02-16Name Statistic_SpecificInformation_02_EndTime&lt;br /&gt;
attr BYD_Status get02-17Name Statistic_SpecificInformation_01_Type&lt;br /&gt;
attr BYD_Status get02-18Name Statistic_SpecificInformation_03_Type&lt;br /&gt;
attr BYD_Status get02-19Name Statistic_SpecificInformation_03_Ah&lt;br /&gt;
attr BYD_Status get02-20Name Statistic_SpecificInformation_03_KWh&lt;br /&gt;
attr BYD_Status get02-21Name Statistic_SpecificInformation_01_Ah&lt;br /&gt;
attr BYD_Status get02-22Name Statistic_SpecificInformation_03_BatTemp&lt;br /&gt;
attr BYD_Status get02-23Name Statistic_SpecificInformation_03_StartTime&lt;br /&gt;
attr BYD_Status get02-24Name Statistic_SpecificInformation_03_EndTime&lt;br /&gt;
attr BYD_Status get02-25Name Statistic_SpecificInformation_01_KWh&lt;br /&gt;
attr BYD_Status get02-26Name Statistic_SpecificInformation_04_Type&lt;br /&gt;
attr BYD_Status get02-27Name Statistic_SpecificInformation_04_Ah&lt;br /&gt;
attr BYD_Status get02-28Name Statistic_SpecificInformation_04_KWh&lt;br /&gt;
attr BYD_Status get02-29Name Statistic_SpecificInformation_01_EnvTemp&lt;br /&gt;
attr BYD_Status get02-2Name Statistic_GeneralInformation_Total_Charge_Energy&lt;br /&gt;
attr BYD_Status get02-30Name Statistic_SpecificInformation_04_BatTemp&lt;br /&gt;
attr BYD_Status get02-31Name Statistic_SpecificInformation_04_StartTime&lt;br /&gt;
attr BYD_Status get02-32Name Statistic_SpecificInformation_04_EndTime&lt;br /&gt;
attr BYD_Status get02-33Name Statistic_SpecificInformation_01_BatTemp&lt;br /&gt;
attr BYD_Status get02-34Name Statistic_SpecificInformation_05_Type&lt;br /&gt;
attr BYD_Status get02-35Name Statistic_SpecificInformation_05_Ah&lt;br /&gt;
attr BYD_Status get02-36Name Statistic_SpecificInformation_05_KWh&lt;br /&gt;
attr BYD_Status get02-37Name Statistic_SpecificInformation_01_StartTime&lt;br /&gt;
attr BYD_Status get02-38Name Statistic_SpecificInformation_05_BatTemp&lt;br /&gt;
attr BYD_Status get02-39Name Statistic_SpecificInformation_05_StartTime&lt;br /&gt;
attr BYD_Status get02-3Name Statistic_SpecificInformation_01_Ah&lt;br /&gt;
attr BYD_Status get02-40Name Statistic_SpecificInformation_05_EndTime&lt;br /&gt;
attr BYD_Status get02-41Name Statistic_SpecificInformation_01_EndTime&lt;br /&gt;
attr BYD_Status get02-49Name Statistic_SpecificInformation_02_Type&lt;br /&gt;
attr BYD_Status get02-4Name Statistic_SpecificInformation_01_KWh&lt;br /&gt;
attr BYD_Status get02-53Name Statistic_SpecificInformation_02_Ah&lt;br /&gt;
attr BYD_Status get02-57Name Statistic_SpecificInformation_02_KWh&lt;br /&gt;
attr BYD_Status get02-5Name Statistic_SpecificInformation_01_EnvTemp&lt;br /&gt;
attr BYD_Status get02-61Name Statistic_SpecificInformation_02_EnvTemp&lt;br /&gt;
attr BYD_Status get02-65Name Statistic_SpecificInformation_02_BatTemp&lt;br /&gt;
attr BYD_Status get02-69Name Statistic_SpecificInformation_02_StartTime&lt;br /&gt;
attr BYD_Status get02-6Name Statistic_SpecificInformation_01_BatTemp&lt;br /&gt;
attr BYD_Status get02-73Name Statistic_SpecificInformation_02_EndTime&lt;br /&gt;
attr BYD_Status get02-7Name Statistic_GeneralInformation_Total_Discharge_Energy&lt;br /&gt;
attr BYD_Status get02-81Name Statistic_SpecificInformation_03_Type&lt;br /&gt;
attr BYD_Status get02-85Name Statistic_SpecificInformation_03_Ah&lt;br /&gt;
attr BYD_Status get02-89Name Statistic_SpecificInformation_03_KWh&lt;br /&gt;
attr BYD_Status get02-8Name Statistic_SpecificInformation_01_EndTime&lt;br /&gt;
attr BYD_Status get02-93Name Statistic_SpecificInformation_03_EnvTemp&lt;br /&gt;
attr BYD_Status get02-97Name Statistic_SpecificInformation_03_BatTemp&lt;br /&gt;
attr BYD_Status get02MaxAge 900&lt;br /&gt;
attr BYD_Status get02MaxAgeReplacementMode delete&lt;br /&gt;
attr BYD_Status get02Name StatisticInformation&lt;br /&gt;
attr BYD_Status get02RegOpt g&lt;br /&gt;
attr BYD_Status get02Regex &amp;lt;td class=&amp;quot;text_l&amp;quot;&amp;gt;(.*)&amp;lt;\/td&amp;gt;\n|Charge Energy:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+.\d+)|Discharge Energy:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+.\d+)|Cycle Counts:&amp;lt;\/td&amp;gt;\n.*&amp;gt;(\d+)&lt;br /&gt;
attr BYD_Status get02URL http://%IP-Address_BYD%/asp/StatisticInformation.asp&lt;br /&gt;
attr BYD_Status get03-10Name DeviceInformation_Machine_Version&lt;br /&gt;
attr BYD_Status get03-10OExpr {$val =~ s/\n//g;; $val}&lt;br /&gt;
attr BYD_Status get03-15Name DeviceInformation_Board_SN&lt;br /&gt;
attr BYD_Status get03-1Name DeviceInformation_Machine_SN&lt;br /&gt;
attr BYD_Status get03-20Name DeviceInformation_Board_Factory_time&lt;br /&gt;
attr BYD_Status get03-8Name DeviceInformation_Machine_Factory_time&lt;br /&gt;
attr BYD_Status get03Name DeviceInformation&lt;br /&gt;
attr BYD_Status get03RegOpt g&lt;br /&gt;
attr BYD_Status get03Regex &amp;gt;(\d{9}-\d{5})&amp;lt;|Version:&amp;lt;\/td&amp;gt;\n&amp;lt;td&amp;gt;(V\d.\d{3}\n [A-Z])&amp;lt;|&amp;gt;SN:&amp;lt;\/td&amp;gt;\n.*&amp;gt;([\d|\w]{18})&amp;lt;|(\d{4}-\d+-\d+ \d+:\d+:\d+)&lt;br /&gt;
attr BYD_Status get03URL http://%IP-Address_BYD%/asp/DeviceInformation.asp&lt;br /&gt;
attr BYD_Status get04-13Name BatteryInformation_SOC&lt;br /&gt;
attr BYD_Status get04-17Name BatteryInformation_SysTemp&lt;br /&gt;
attr BYD_Status get04-1Name BatteryInformation_TotalVoltage&lt;br /&gt;
attr BYD_Status get04-21Name BatteryInformation_MaxCellVol&lt;br /&gt;
attr BYD_Status get04-25Name BatteryInformation_MinCellVol&lt;br /&gt;
attr BYD_Status get04-29Name BatteryInformation_MaxCellTemp&lt;br /&gt;
attr BYD_Status get04-33Name BatteryInformation_MinCellTemp&lt;br /&gt;
attr BYD_Status get04-37Name BatteryInformation_Power&lt;br /&gt;
attr BYD_Status get04-42Name BatteryInformation_System_state&lt;br /&gt;
attr BYD_Status get04-47Name BatteryInformation_Date_and_Time&lt;br /&gt;
attr BYD_Status get04-52Name BatteryInformation_Alarm_state&lt;br /&gt;
attr BYD_Status get04-5Name BatteryInformation_PackVoltage&lt;br /&gt;
attr BYD_Status get04-9Name BatteryInformation_Current&lt;br /&gt;
attr BYD_Status get04MaxAge 900&lt;br /&gt;
attr BYD_Status get04MaxAgeReplacementMode delete&lt;br /&gt;
attr BYD_Status get04Name BatteryInformation&lt;br /&gt;
attr BYD_Status get04RegOpt g&lt;br /&gt;
attr BYD_Status get04Regex value=([+|-]{0,1}\d+.\d+)[%]{0,1}&amp;gt;|value=([A-Z]+)&amp;gt;|value=&amp;quot;(\d{4}-\d+-\d+ \d+:\d+:\d+)&amp;quot;|Alarm state:&amp;lt;\/h3&amp;gt;&amp;lt;\/td&amp;gt;\n&amp;lt;td&amp;gt;.*&amp;quot;&amp;gt;(\w+\W)&amp;lt;\/font&amp;gt;&lt;br /&gt;
attr BYD_Status get04URL http://%IP-Address_BYD%/asp/Home.asp&lt;br /&gt;
attr BYD_Status getHeader01 Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=MD5, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=&amp;quot;auth&amp;quot;, nc=%auth_nc%, cnonce=&amp;quot;%auth_cnonce%&amp;quot;&lt;br /&gt;
attr BYD_Status group PV Eigenverbrauch&lt;br /&gt;
attr BYD_Status httpVersion 1.1&lt;br /&gt;
attr BYD_Status icon measure_battery_100&lt;br /&gt;
attr BYD_Status reAuthRegex Unauthorized&lt;br /&gt;
attr BYD_Status reading01Name auth_qop&lt;br /&gt;
attr BYD_Status reading01Regex qop=&amp;quot;(.*)&amp;quot;, nonce&lt;br /&gt;
attr BYD_Status reading02Name auth_nonce&lt;br /&gt;
attr BYD_Status reading02Regex nonce=&amp;quot;(.*)&amp;quot;, opaque&lt;br /&gt;
&lt;br /&gt;
attr BYD_Status reading03Name auth_opaque&lt;br /&gt;
attr BYD_Status reading03Regex opaque=&amp;quot;(.*)&amp;quot;,algorithm&lt;br /&gt;
attr BYD_Status reading04Name auth_realm&lt;br /&gt;
attr BYD_Status reading04Regex realm=&amp;quot;(.*)&amp;quot;, domain&lt;br /&gt;
attr BYD_Status replacement01Mode expression&lt;br /&gt;
attr BYD_Status replacement01Regex %IP-Address_BYD%&lt;br /&gt;
attr BYD_Status replacement01Value ReadingsVal(&amp;quot;PV_Anlage_1_config&amp;quot;,&amp;quot;IP-Address_BYD&amp;quot;,&amp;quot;&amp;quot;)&lt;br /&gt;
attr BYD_Status replacement03Mode reading&lt;br /&gt;
attr BYD_Status replacement03Regex %auth_realm%&lt;br /&gt;
attr BYD_Status replacement03Value auth_realm&lt;br /&gt;
attr BYD_Status replacement04Mode reading&lt;br /&gt;
attr BYD_Status replacement04Regex %auth_nonce%&lt;br /&gt;
attr BYD_Status replacement04Value auth_nonce&lt;br /&gt;
attr BYD_Status replacement05Mode reading&lt;br /&gt;
attr BYD_Status replacement05Regex %auth_response%&lt;br /&gt;
attr BYD_Status replacement05Value auth_response&lt;br /&gt;
attr BYD_Status replacement06Mode reading&lt;br /&gt;
attr BYD_Status replacement06Regex %auth_opaque%&lt;br /&gt;
attr BYD_Status replacement06Value auth_opaque&lt;br /&gt;
attr BYD_Status replacement07Mode reading&lt;br /&gt;
attr BYD_Status replacement07Regex %auth_nc%&lt;br /&gt;
attr BYD_Status replacement07Value auth_nc&lt;br /&gt;
attr BYD_Status replacement08Mode reading&lt;br /&gt;
attr BYD_Status replacement08Regex %auth_cnonce%&lt;br /&gt;
attr BYD_Status replacement08Value auth_cnonce&lt;br /&gt;
attr BYD_Status room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr BYD_Status showBody 1&lt;br /&gt;
attr BYD_Status showError 1&lt;br /&gt;
attr BYD_Status sid01Header Authorization: Digest username=&amp;quot;installer&amp;quot;, realm=&amp;quot;%auth_realm%&amp;quot;, nonce=&amp;quot;%auth_nonce%&amp;quot;, uri=&amp;quot;/asp/RunData.asp&amp;quot;, algorithm=MD5, response=&amp;quot;%auth_response%&amp;quot;, opaque=&amp;quot;%auth_opaque%&amp;quot;, qop=auth, nc=%auth_nc%, cnonce=&amp;quot;%auth_cnonce%&amp;quot;&lt;br /&gt;
attr BYD_Status sid01ParseResponse 1&lt;br /&gt;
attr BYD_Status sid01URL http://%IP-Address_BYD%/asp/RunData.asp&lt;br /&gt;
attr BYD_Status sortby 02&lt;br /&gt;
attr BYD_Status stateFormat {round(ReadingsVal(&amp;quot;BYD_Status&amp;quot;,&amp;quot;BatteryInformation_SOC&amp;quot;,0),0)}&lt;br /&gt;
attr BYD_Status userReadings auth_first_called:auth_nonce.* {my $first_called = InternalVal(&amp;quot;$NAME&amp;quot;,&amp;quot;path&amp;quot;,&amp;quot;n.a&amp;quot;);;;; $first_called =~ s/:/_/g;;;;$first_called ;;;;$first_called =~ s/\/api\/v1//g;;;;;;;;$first_called},\&lt;br /&gt;
auth_HA1:auth_first_called.* {md5_hex(&amp;quot;installer:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_realm&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;lt;Password&amp;gt;&amp;quot;)},\&lt;br /&gt;
auth_HA2:auth_HA1.* {md5_hex(&amp;quot;GET:/asp/RunData.asp&amp;quot;)},\&lt;br /&gt;
auth_response:auth_HA2.* {md5_hex(ReadingsVal($NAME,&amp;quot;auth_HA1&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_nc&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_cnonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_qop&amp;quot;,&amp;quot;&amp;quot;).&amp;quot;:&amp;quot;.ReadingsVal($NAME,&amp;quot;auth_HA2&amp;quot;,&amp;quot;&amp;quot;))},\&lt;br /&gt;
auth_nc:auth_response.* {&amp;quot;00000001&amp;quot;},\&lt;br /&gt;
auth_cnonce:auth_response.* {&amp;quot;d789ea5b7e9a2377&amp;quot;},\&lt;br /&gt;
auth_Step1_Message:auth_nonce.* {&amp;quot;HTTP nonce updated&amp;quot;},\&lt;br /&gt;
Specific_Information_00_Date:Statistic_SpecificInformation_05_EndTime.* { fhem(&amp;quot;deletereading &amp;quot;.$NAME.&amp;quot; StatisticInformation.*&amp;quot;);;;; localtime()}\&lt;br /&gt;
## auth_Step2_Message:auth_Step1_Message.* { fhem(&amp;quot;get &amp;quot;.$NAME.&amp;quot; RunData&amp;quot;) ;;;; &amp;quot;HTTP Request RunData called&amp;quot; }\&lt;br /&gt;
&lt;br /&gt;
attr BYD_Status verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Timeing für die PV extra Funktionen ==&lt;br /&gt;
=== RAW Definition PV_Schedule (DOIF) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Schedule DOIF ################################################################################################################\&lt;br /&gt;
## 1 BYD Status aktualisieren\&lt;br /&gt;
##\&lt;br /&gt;
 ([+:06] and !([:00] or [:30]))\&lt;br /&gt;
   (\&lt;br /&gt;
      get BYD_Status RunData\&lt;br /&gt;
   )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Plenticore Status aktualisieren. Dies geschieht über das PV_Anlage_1_API Device\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([:57])\&lt;br /&gt;
   (\&lt;br /&gt;
   get PV_Anlage_1_API 20_/processdata/scb_statistic_EnergyFlow\&lt;br /&gt;
   )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 PV Prognose vom aktuellen Tag aktualisieren\&lt;br /&gt;
##     zwischen 7 und 19 Uhr zur vollen Stunde\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([07:00-20:00] and [:00])\&lt;br /&gt;
   (\&lt;br /&gt;
    {Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_delete_PV_Forecast&amp;quot;,&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,0)}\&lt;br /&gt;
   )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 PV Prognose für den nächsten Tag aktualisieren\&lt;br /&gt;
## \&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([06:55] or [19:11])\&lt;br /&gt;
   (\&lt;br /&gt;
    {Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_delete_PV_Forecast&amp;quot;,&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Forecast&amp;quot;,1)}\&lt;br /&gt;
   )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 regelmäßig die Bilanz aktualisieren\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([08:00-20:00] and [+:05] and ![:00]) ## Tagsüber alle 5 Minuten außer um :00\&lt;br /&gt;
  (\&lt;br /&gt;
   set Dum.Energy update\&lt;br /&gt;
  )&lt;br /&gt;
attr PV_Schedule DbLogExclude .*&lt;br /&gt;
attr PV_Schedule alias PV_Schedule&lt;br /&gt;
attr PV_Schedule cmdState BYD Status|Plenticore Status&lt;br /&gt;
attr PV_Schedule do always&lt;br /&gt;
attr PV_Schedule room Strom-&amp;gt;System&lt;br /&gt;
attr PV_Schedule sortby 11&lt;br /&gt;
attr PV_Schedule verbose 0&lt;br /&gt;
attr PV_Schedule wait 0:0:0:0:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Energie Bilanz ==&lt;br /&gt;
[[Bild:Plenticore Bilanz.png|mini|900px|rechts|]]&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions und Verbrauchswerte Liefern. Hierbei werden die Momentanwerte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt.&lt;br /&gt;
Die Aktualisierung erfolgt zyklisch über das Gerät PV_Schedule.&lt;br /&gt;
=== RAW Definition Energiebilanz ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Dum.Energy dummy&lt;br /&gt;
attr Dum.Energy DbLogExclude .*&lt;br /&gt;
attr Dum.Energy DbLogInclude Autarky.*,GridFeed.*,PV.*,.*Consumption.*&lt;br /&gt;
attr Dum.Energy alias Energiebilanz&lt;br /&gt;
attr Dum.Energy comment TotalConsumption,AutarkyQuoteDay,SelfConsumptionQuoteDay,AutarkyQuoteMonth,SelfConsumptionQuoteMonth&lt;br /&gt;
attr Dum.Energy event-on-change-reading PV,GridConsumption,GridFeedIn,SelfConsumptionQuote,Autarky.*,GridFeed.*,PV.*,.*Consumption.*&lt;br /&gt;
attr Dum.Energy event-on-update-reading TotalConsumption,AutarkyQuoteDay,SelfConsumptionQuoteDay,AutarkyQuoteMonth,SelfConsumptionQuoteMonth&lt;br /&gt;
attr Dum.Energy group Energiebilanz&lt;br /&gt;
attr Dum.Energy icon measure_power_meter&lt;br /&gt;
attr Dum.Energy room Strom-&amp;gt;Energie&lt;br /&gt;
attr Dum.Energy stateFormat {\&lt;br /&gt;
 my $pvt   = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVTotal&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $pvtd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVTotalDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $pvtm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVTotalMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $pvty  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVTotalYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $pv  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PV&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $pvd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $pvm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $pvy  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $gfi  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridFeedIn&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $gfid = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridFeedInDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $gfim = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridFeedInMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $gfiy = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridFeedInYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $eb   = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridConsumption&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $ebd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridConsumptionDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $ebm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridConsumptionMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $eby  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridConsumptionYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $et   = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;TotalConsumption&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $etd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;TotalConsumptionDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $etm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;TotalConsumptionMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $ety  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;TotalConsumptionYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $aq   = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;AutarkyQuote&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $aqd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;AutarkyQuoteDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $aqm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;AutarkyQuoteMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $aqy  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;AutarkyQuoteYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $sq   = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SelfConsumptionQuote&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $sqd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SelfConsumptionQuoteDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $sqm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SelfConsumptionQuoteMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $sqy  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SelfConsumptionQuoteYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $md   = ReadingsTimestamp(&amp;quot;$name&amp;quot;, &amp;quot;AutarkyQuote&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
 my $cd   = ReadingsTimestamp(&amp;quot;PV_Anlage_1_API&amp;quot;, &amp;quot;Statistic_Autarky_Day&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
 my $cm   = ReadingsTimestamp(&amp;quot;PV_Anlage_1_API&amp;quot;, &amp;quot;Statistic_Autarky_Month&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
 my $cy   = ReadingsTimestamp(&amp;quot;PV_Anlage_1_API&amp;quot;, &amp;quot;Statistic_Autarky_Year&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt; &amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;aktueller Wert&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;Heute&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;dieser Monat&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;dieses Jahr&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;PV-Erzeugung-Total&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvt.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvtd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvtm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvty.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;PV-Einspeisung&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$gfi.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$gfid.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$gfim.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$gfiy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Netz-Bezug&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$eb.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$ebd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$ebm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$eby.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;PV-Bezug&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pv.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Energieverbrauch&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$et.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$etd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$etm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$ety.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Autarkiequote&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$aq.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$aqd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$aqm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$aqy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Eigenverbrauchsquote&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$sq.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$sqd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$sqm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$sqy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Berechnung am&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$md.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$cd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$cm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$cy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;/table&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr Dum.Energy userReadings PVTotal {round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_AC_active_power&amp;quot;,&amp;quot;&amp;quot;),0)},\&lt;br /&gt;
PVTotalDay {round( ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;, &amp;quot;&amp;quot;)/1000 ,2)},\&lt;br /&gt;
PVTotalMonth {round( ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;, &amp;quot;&amp;quot;)/1000 ,2)},\&lt;br /&gt;
PVTotalYear {round( ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;, &amp;quot;&amp;quot;)/1000 ,2)},\&lt;br /&gt;
\&lt;br /&gt;
PV {round( ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_battery&amp;quot;, &amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_PV&amp;quot;, &amp;quot;&amp;quot;) ,0)},\&lt;br /&gt;
PVDay {round( (ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;, &amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;, &amp;quot;&amp;quot;))/1000 ,2)},\&lt;br /&gt;
PVMonth {round( (ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;, &amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;, &amp;quot;&amp;quot;))/1000 ,2)},\&lt;br /&gt;
PVYear {round( (ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;, &amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;, &amp;quot;&amp;quot;))/1000 ,2)},\&lt;br /&gt;
\&lt;br /&gt;
GridFeedIn { ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0)&amp;lt;=0 ? abs(round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0),0)) : 0  },\&lt;br /&gt;
GridFeedInDay {round((ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;, &amp;quot;&amp;quot;))/1000,2)},\&lt;br /&gt;
GridFeedInMonth {round((ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;, &amp;quot;&amp;quot;))/1000,2)},\&lt;br /&gt;
GridFeedInYear {round((ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;, &amp;quot;&amp;quot;))/1000,2)},\&lt;br /&gt;
\&lt;br /&gt;
GridConsumption { ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0)&amp;gt;=0 ? round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0),0) : 0  },\&lt;br /&gt;
GridConsumptionDay {round(abs(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Day&amp;quot;,&amp;quot;&amp;quot;))/1000 ,2)},\&lt;br /&gt;
GridConsumptionMonth {round(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Month&amp;quot;,&amp;quot;&amp;quot;)/1000 ,2)},\&lt;br /&gt;
GridConsumptionYear {round(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Year&amp;quot;,&amp;quot;&amp;quot;)/1000 ,2)},\&lt;br /&gt;
\&lt;br /&gt;
TotalConsumption {round((ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_PV&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_battery&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_grid&amp;quot;,&amp;quot;&amp;quot;)),0)},\&lt;br /&gt;
\&lt;br /&gt;
TotalConsumptionDay {round( (ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Day&amp;quot;,&amp;quot;&amp;quot;) )/1000 ,2)},\&lt;br /&gt;
TotalConsumptionMonth {round( (ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Month&amp;quot;,&amp;quot;&amp;quot;) )/1000 ,2)},\&lt;br /&gt;
TotalConsumptionYear {round( (ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Year&amp;quot;,&amp;quot;&amp;quot;) )/1000,2)},\&lt;br /&gt;
\&lt;br /&gt;
AutarkyQuote {my $valA = ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;, &amp;quot;Total_AC_active_power&amp;quot;,&amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;, &amp;quot;Home_own_consumption_from_grid&amp;quot;,&amp;quot;&amp;quot;);;;; my $calcVal = ($valA &amp;gt; 0)?round($valA /($valA + ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;, &amp;quot;Home_own_consumption_from_grid&amp;quot;,&amp;quot;&amp;quot;))*100 ,0) : 0 ;;;; ($calcVal &amp;gt; 100)?100:$calcVal },\&lt;br /&gt;
AutarkyQuoteDay {round(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Autarky_Day&amp;quot;, &amp;quot;&amp;quot;),0)},\&lt;br /&gt;
AutarkyQuoteMonth {round(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Autarky_Month&amp;quot;, &amp;quot;&amp;quot;),0)},\&lt;br /&gt;
AutarkyQuoteYear {round(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Autarky_Year&amp;quot;, &amp;quot;&amp;quot;),0)},\&lt;br /&gt;
\&lt;br /&gt;
SelfConsumptionQuote {my $valS = ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_AC_active_power&amp;quot;, 0) ;;;; my $calcVal = ($valS &amp;gt; 0)?round((ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_PV&amp;quot;, &amp;quot;0&amp;quot;) + ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_battery&amp;quot;,&amp;quot;0&amp;quot;)) / $valS * 100 ,0) : 0 ;;;; ($calcVal &amp;gt; 100)?100:$calcVal},\&lt;br /&gt;
SelfConsumptionQuoteDay {round(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_OwnConsumptionRate_Day&amp;quot;, &amp;quot;&amp;quot;),0)},\&lt;br /&gt;
SelfConsumptionQuoteMonth {round(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_OwnConsumptionRate_Month&amp;quot;, &amp;quot;&amp;quot;),0)},\&lt;br /&gt;
SelfConsumptionQuoteYear {round(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_OwnConsumptionRate_Year&amp;quot;, &amp;quot;&amp;quot;),0)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Erstellen von zusätzlichen Werten in der Datenbank ===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|900px|rechts|Die Definitiun diese Diagramms ist weiter unten beschrieben.]]&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
==== RAW Definition LogDBRep_PV_total_diff_Week ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_total_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week device Dum.Energy&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week reading PVTotalMonth&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition LogDBRep_PV_total_max_Month ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_total_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_total_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_total_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_PV_total_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_total_max_Month device Dum.Energy&lt;br /&gt;
attr LogDBRep_PV_total_max_Month reading PVTotalMonth&lt;br /&gt;
attr LogDBRep_PV_total_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_PV_total_max_Month timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_PV_total_max_Month timestamp_end previous_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition LogDBRep_PV_used_diff_Week ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_used_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week device Dum.Energy&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week reading PVMonth&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition LogDBRep_PV_used_max_Month ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_used_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_used_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_used_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_PV_used_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_used_max_Month device Dum.Energy&lt;br /&gt;
attr LogDBRep_PV_used_max_Month reading PVMonth&lt;br /&gt;
attr LogDBRep_PV_used_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_PV_used_max_Month timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_PV_used_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Timing für die Datenbank Einträge ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DF_DB_Service DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))(\&lt;br /&gt;
  set LogDBRep_PV_used_max_Month maxValue writeToDB;;\&lt;br /&gt;
  set LogDBRep_PV_total_max_Month maxValue writeToDB\&lt;br /&gt;
  )\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))(\&lt;br /&gt;
  set LogDBRep_PV_used_diff_Week diffValue writeToDB;;\&lt;br /&gt;
  set LogDBRep_PV_total_diff_Week diffValue writeToDB\&lt;br /&gt;
  )\&lt;br /&gt;
&lt;br /&gt;
attr DF_DB_Service DbLogExclude .*&lt;br /&gt;
attr DF_DB_Service do always&lt;br /&gt;
attr DF_DB_Service room System&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Löschen von nicht mehr benötigten Werten in der Datenbank ===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen trend erkennen lassen.&lt;br /&gt;
Wen eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wetter-/Leistungs-Prognose ==&lt;br /&gt;
Dies ist ein Thema, dass nicht wirklich gut zu fassen ist und ist eher etwas für Enthusiasten :-), wer schon mal mit Sonne, Wolken und Regen gerechnet hat versteht was ich meine. Dieser Ansatz ist nicht wissenschaftlicher Art und hat auch keinen Anspruch mathematischer Perfektion. Nach reinem Gefühl und mit aus dem Fenster schauen kommt jedoch ein respektables Ergebnis dabei heraus. Viel Vergnügen und Spaß beim mitbasteln ;-)&lt;br /&gt;
[[Bild:Plenticore_Forecast_Tagesanfang.png|mini|900px|rechts|Wenn der Tag begonnen hat ist die Prognose vom Vortag bereits im Diagramm. Der Wert Calculation in schwarz ist die aktuelle Korrektur.]]&lt;br /&gt;
=== Deutscher Wetter Dienst (DWD) ===&lt;br /&gt;
Der DWD liefert über Mosmix kostenlos, stunden aktuelle Prognosedaten woraus für diese Anwendung die Werte Rad1h und TTT bezogen werden. In der Funktion Solar_forecast erfolgt noch eine Verschiebung um eine Stunde und die Umrechnung von Rad1h in Watt/m² .&lt;br /&gt;
&#039;&#039;&#039;Achtung: nicht alle Stationen liefern auch die Rad1h Daten, was deshalb bitte anhand der readings kontrolliert werden müsste.&#039;&#039;&#039;&lt;br /&gt;
[[DWD_OpenData|FHEM DWD_OpenData Modul]]&lt;br /&gt;
==== RAW Definition DWD_Forecast ====&lt;br /&gt;
Erfordert ggf.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt-get install libxml-libxml-perl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DWD_Forecast DWD_OpenData&lt;br /&gt;
attr DWD_Forecast DbLogExclude .*&lt;br /&gt;
attr DWD_Forecast forecastDays 1&lt;br /&gt;
attr DWD_Forecast forecastProperties Rad1h,TTT,Neff,R600&lt;br /&gt;
attr DWD_Forecast forecastResolution 1&lt;br /&gt;
attr DWD_Forecast forecastStation P0178&lt;br /&gt;
attr DWD_Forecast group PV Eigenverbrauch&lt;br /&gt;
attr DWD_Forecast icon weather_rain_fog&lt;br /&gt;
attr DWD_Forecast room Informationen-&amp;gt;Wetter,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr DWD_Forecast sortby 02&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 99_myUtils.pm Funktionen ===&lt;br /&gt;
==== Solar_forecast ====&lt;br /&gt;
Achtung, diese Funktion ist noch nicht vollständig ausprogrammiert. Es wurden bereits Übergabeparameter integriert, um z.B. andere Wetterdienste zu berücksichtigen.&lt;br /&gt;
Um diese Funktion zu nutzen muss ein Dummy PV_Anlage_1_config vorhanden sein, in dem unter anderem die Modul und Anlagen Ausrichtung konfiguriert wird.&lt;br /&gt;
Rückfragen gerne im Forum.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
###########################################################&lt;br /&gt;
# Subroutine to calculate radiation&lt;br /&gt;
###########################################################&lt;br /&gt;
sub Solar_forecast($$$$$$) {&lt;br /&gt;
#&lt;br /&gt;
#    Mit &amp;quot;attr global verbose 3&amp;quot; erscheinen Logmeldungen&lt;br /&gt;
#&lt;br /&gt;
     my $logdb       = $_[0] ;&lt;br /&gt;
     my $logdbrep    = $_[1] ;        # Das wird zum Löschen in der LogDB verwendet und muss entsprechend konfiguriert sein.&lt;br /&gt;
     my $logdevice   = $_[2] ;&lt;br /&gt;
     # Hier könnte man noch andere Wetterdienste berücksichtigen bzw den Device Namen ändern&lt;br /&gt;
     my $wetter      = $_[4] ; if ($wetter ne &amp;quot;DWD_Forecast&amp;quot;) {return(&amp;quot;$wetter not supported&amp;quot;)} ;&lt;br /&gt;
     my $fc          = $_[5] ;        # Wieviel Tage in die Zukunft soll es gehen? 0,1,2&lt;br /&gt;
     my $reading     = $_[3].$fc ;&lt;br /&gt;
&lt;br /&gt;
     my $timeshift = 1;               # Verschiebt die Prognose um eine Stunde&lt;br /&gt;
     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $year += 1900; $mon += 1;&lt;br /&gt;
     my ($Solar_Cloud,$Solar_Rain,$Solar_Temp,$Solar_SolarRadiation,$logentry,$i) = (0) x 6 ;&lt;br /&gt;
     my ($cloudk,$raink,$tempk,$cloudk_base,$raink_base,$tempk_base) = (0) x 6 ;&lt;br /&gt;
     my ($Solar_Correction_Cloud,$Solar_Correction_Rain,$Solar_Correction_Temp,$Solar_Plain) = (1) x 4 ;&lt;br /&gt;
     my (@Solar_,@module_count) = (0,0,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Initialisieren des Basis TIMESTAMP für den Forecast&lt;br /&gt;
     my $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; 07:00:00&amp;quot;) ;&lt;br /&gt;
     my $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
     # Bei Forecast zuerst die bisherigen Einträge in der Datenbank für den Tag löschen&lt;br /&gt;
     fhem &amp;quot;set &amp;quot;.$logdbrep.&amp;quot; sqlCmd DELETE FROM history WHERE DEVICE=&#039;&amp;quot;.$logdevice.&amp;quot;&#039; AND READING=&#039;&amp;quot;.$reading.&amp;quot;&#039; AND TIMESTAMP&amp;gt;=&#039;&amp;quot;.$timestamp.&amp;quot;&#039;&amp;quot; ;&lt;br /&gt;
&lt;br /&gt;
      # Es werden Stundenwerte von 07:00 bis 19:00 Uhr berechnet&lt;br /&gt;
      for ($i = 7; $i &amp;lt;= 19; $i++) {&lt;br /&gt;
        $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; &amp;quot;.$i.&amp;quot;:00:00&amp;quot;) ;&lt;br /&gt;
        $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
        if ( $wetter eq &amp;quot;DWD_Forecast&amp;quot;) {&lt;br /&gt;
          $Solar_Cloud          = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Neff&amp;quot; ,0);&lt;br /&gt;
          $Solar_Rain           = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_R600&amp;quot; ,0);&lt;br /&gt;
          $Solar_Temp           = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_TTT&amp;quot;  ,0)+10;&lt;br /&gt;
          $Solar_SolarRadiation = ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Rad1h&amp;quot;,0);&lt;br /&gt;
          $Solar_SolarRadiation = round($Solar_SolarRadiation * 0.277778 ,0);&lt;br /&gt;
          Log 3, &amp;quot;Solar_SolarRadiation   :  &amp;quot;.$Solar_SolarRadiation.&amp;quot; &amp;quot;.ReadingsVal($wetter,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_&amp;quot;.($i+$timeshift).&amp;quot;_Rad1h&amp;quot;,0) ;&lt;br /&gt;
         };&lt;br /&gt;
&lt;br /&gt;
        $cloudk = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
        if ($cloudk ne 0) {&lt;br /&gt;
          $cloudk_base = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk_base&amp;quot;,0) ;&lt;br /&gt;
          $Solar_Correction_Cloud = round((1 + ($Solar_Cloud - $cloudk_base) * $cloudk / 100),3) ;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        $raink  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink&amp;quot;,0) * -0.01 ;&lt;br /&gt;
        if ($raink ne 0) {&lt;br /&gt;
          $raink_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink_base&amp;quot; ,0) ;&lt;br /&gt;
          $Solar_Correction_Rain = round((1 + ($Solar_Rain  - $raink_base ) * $raink  / 100),3) ;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        $tempk  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
        if ($tempk ne 0) {&lt;br /&gt;
          $tempk_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk_base&amp;quot; ,0) ;&lt;br /&gt;
          $Solar_Correction_Temp = round((1 + ($Solar_Temp  - $tempk_base ) * $tempk  / 100),3) ;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        my $Solar_Correction_Faktor = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_factor&amp;quot;,1) ;&lt;br /&gt;
&lt;br /&gt;
        $logentry = 0 ;&lt;br /&gt;
        for(my $j=1;$j&amp;lt;4;$j++){&lt;br /&gt;
          $module_count[$j] = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_count&amp;quot;,0) ;&lt;br /&gt;
          if ($module_count[$j] ne 0) {&lt;br /&gt;
            $Solar_Plain = round(Solar_plain(ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0) , ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0) , $timestamp),3) ;&lt;br /&gt;
            Log 3, &amp;quot;plain/direction        :  &amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0).&amp;quot;/&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0).&amp;quot; &amp;gt;&amp;gt;&amp;gt; &amp;quot;.$Solar_Plain ;&lt;br /&gt;
&lt;br /&gt;
            $Solar_[$j]  = $module_count[$j] * ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_power&amp;quot;,1)/1000 ;&lt;br /&gt;
            $Solar_[$j]  = $Solar_[$j] * $Solar_Plain ;&lt;br /&gt;
            $Solar_[$j]  = $Solar_[$j] * $Solar_SolarRadiation ;&lt;br /&gt;
            $Solar_[$j]  = $Solar_[$j] * $Solar_Correction_Temp * $Solar_Correction_Cloud * $Solar_Correction_Rain * $Solar_Correction_Faktor ;&lt;br /&gt;
            $Solar_[$j]  = ($Solar_[$j] lt 0)?0:round($Solar_[$j],0) ;&lt;br /&gt;
          };&lt;br /&gt;
          $logentry = $logentry + $Solar_[$j] ;&lt;br /&gt;
          if ($fc == 0 and $hour == $i) {&lt;br /&gt;
            fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_name&amp;quot;,0).&amp;quot; &amp;quot;.$Solar_[$j] ;&lt;br /&gt;
          };&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        fhem &amp;quot;set &amp;quot;.$logdb.&amp;quot; addCacheLine &amp;quot;.$timestamp.&amp;quot;|&amp;quot;.$logdevice.&amp;quot;|addlog|&amp;quot;.$reading.&amp;quot;: &amp;quot;.$logentry.&amp;quot;|&amp;quot;.$reading.&amp;quot;|&amp;quot;.$logentry.&amp;quot;|&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        if ($fc == 0 and $hour == $i and ($module_count[1] ne 0 or $module_count[2] ne 0 or $module_count[3] ne 0)) {&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_SolarRadiation &amp;quot;.$Solar_SolarRadiation ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Cloud &amp;quot;.$Solar_Cloud ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Rain &amp;quot;.$Solar_Rain ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Temp &amp;quot;.$Solar_Temp ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Correction_Cloud &amp;quot;.$Solar_Correction_Cloud ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Correction_Rain &amp;quot;.$Solar_Correction_Rain ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Correction_Temp &amp;quot;.$Solar_Correction_Temp ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Calculation &amp;quot;.$logentry ;&lt;br /&gt;
        } ;&lt;br /&gt;
&lt;br /&gt;
        Log 3, &amp;quot;Solar_Plain            : &amp;quot;.$Solar_Plain ;&lt;br /&gt;
        Log 3, &amp;quot;Solar_SolarRadiation   : &amp;quot;.$Solar_SolarRadiation ;&lt;br /&gt;
        Log 3, &amp;quot;Solar_Cloud            : &amp;quot;.$Solar_Cloud ;&lt;br /&gt;
        Log 3, &amp;quot;cloudk                 : &amp;quot;.$cloudk.&amp;quot; &amp;quot;.$cloudk_base ;&lt;br /&gt;
        Log 3, &amp;quot;Solar_Correction_Cloud : &amp;quot;.$Solar_Correction_Cloud ;&lt;br /&gt;
        Log 3, &amp;quot;Solar_Rain             : &amp;quot;.$Solar_Rain ;&lt;br /&gt;
        Log 3, &amp;quot;raink                  : &amp;quot;.$raink.&amp;quot; &amp;quot;.$raink_base ;&lt;br /&gt;
        Log 3, &amp;quot;Solar_Correction_Rain  : &amp;quot;.$Solar_Correction_Rain ;&lt;br /&gt;
        Log 3, &amp;quot;Solar_Temp             : &amp;quot;.$Solar_Temp ;&lt;br /&gt;
        Log 3, &amp;quot;tempk                  : &amp;quot;.$tempk.&amp;quot; &amp;quot;.$tempk_base ;&lt;br /&gt;
        Log 3, &amp;quot;Solar_Correction_Temp  : &amp;quot;.$Solar_Correction_Temp ;&lt;br /&gt;
        Log 3, $fc.&amp;quot; &amp;quot;.$i.&amp;quot; &amp;quot;.$Solar_SolarRadiation.&amp;quot; &amp;quot;.$logentry ;&lt;br /&gt;
      } ;&lt;br /&gt;
    return (0);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Solar_Plain ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub Solar_plain($$$) {&lt;br /&gt;
&lt;br /&gt;
        my $angle       = $_[0];&lt;br /&gt;
        my $orienta     = $_[1];&lt;br /&gt;
        my $time        = $_[2];&lt;br /&gt;
        my $azimuth     = fhem &amp;quot;get Astro text SunAz &amp;quot;.$time ;&lt;br /&gt;
&lt;br /&gt;
# angles in radiant&lt;br /&gt;
        my $rad         = 57.296;&lt;br /&gt;
        my $elevation   = fhem &amp;quot;get Astro text SunAlt &amp;quot;.$time ;&lt;br /&gt;
           $elevation   = $elevation / $rad;&lt;br /&gt;
        $angle          = $angle     / $rad;&lt;br /&gt;
        my $orientation = ($azimuth - 180 - $orienta) / $rad;&lt;br /&gt;
&lt;br /&gt;
#  avoid unrealistic values (normally formula should only be used within boundaries of orientation +/- 90 degrees)&lt;br /&gt;
        return (0.001) if ($elevation &amp;lt;= 0.25); &lt;br /&gt;
&lt;br /&gt;
        if(cos($orientation) &amp;lt; 0.05 &amp;amp;&amp;amp; cos($orientation) &amp;gt; -0.2) {$orientation =$orientation - 0.2};&lt;br /&gt;
&lt;br /&gt;
#    Log3 &amp;quot;&amp;quot;, 1, &amp;quot;Solar radiation, azimuth = $azimuth, orientation=$orientation, elevation=$elevation, angle=$angle&amp;quot;;&lt;br /&gt;
     my $factor = sin($angle) /&lt;br /&gt;
         (sin( $elevation) / &lt;br /&gt;
          cos( $elevation)) * &lt;br /&gt;
        cos($orientation) +&lt;br /&gt;
                cos($angle);&lt;br /&gt;
&lt;br /&gt;
# otherwise too big values (normally formula should only be used within boundaries of orientation +/- 90 degrees)&lt;br /&gt;
    if ($factor &amp;gt; - 0.05 &amp;amp;&amp;amp; $factor &amp;lt; 0.05) {$factor = 0.05};&lt;br /&gt;
&lt;br /&gt;
    return ($factor);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== wunderground ===&lt;br /&gt;
Diesen Dienst nutze ich nicht für die Prognose, jedoch kann man dort private Wetterstationen in seinem näheren Umfeld finden, die die Sonneneinstrahlung und den UV Index messen. Das ist dann als aktueller Wert in den Diagrammen zu sehen und lässt aktuelle Beschattung durch Wolken erkennen. Hier kann man dann auch mehrere Stationen definieren und eventuell mit einem Durchschnitt arbeiten, wenn nicht gerade der Nachbar eine Station hat.&lt;br /&gt;
Für diese Abfrage ist keine Registrierung notwendig und man muss auch nicht selber mir einer Station Daten liefern.&lt;br /&gt;
Aber bitte, die Abfrage nicht in einem zu kurzen Abstand, also mit hoher Frequenz stellen! Hier wird alle 15 Minuten (900 Sekunden) abgefragt.&lt;br /&gt;
=== RAW Definition Wetter_&amp;lt;Wohnort&amp;gt; ===&lt;br /&gt;
Ggf. muss UConv vorher noch aktiviert werden:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
define uconvInit notify global:INITIALIZED {use UConv}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod wetter_&amp;lt;Wohnort&amp;gt; HTTPMOD https://www.wunderground.com/dashboard/pws/&amp;lt;Wohnort_Station&amp;gt; 900&lt;br /&gt;
&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogExclude .*&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogInclude solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; alias wetter_&amp;lt;Wohnort&amp;gt;&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; enableControlSet 1&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; event-on-change-reading solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; group ASC Environment&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; icon weather_sunrise&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Name date&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Regex Summary.*&amp;gt;([[:alpha:]]{1,8} [\d]{1,2}, [\d]{4})&amp;lt;.*Temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Name dewpointTemperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;.*HUMIDITY&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Name dewpointTemperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;.*HUMIDITY&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Name humidity&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Regex HUMIDITY.*&amp;gt;([\d\.]+)&amp;lt;.*WIND&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Name precip1hrmetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Regex PRECIP RATE.*&amp;gt;([\d\.]+)&amp;lt;.*PRECIP TOTAL&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Name preciptodaymetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Regex PRECIP TOTAL.*&amp;gt;([\d\.]+)&amp;lt;.*tile-precipitation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Name pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07OExpr UConv::inhg2hpa($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Name pressure_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Name solarRadiation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Regex SOLAR RADIATION.*CURRENT.*weather__text&amp;quot;&amp;gt;([\d\.]+)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Name solarUV&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Regex CURRENT UV.*&amp;gt;([\d\.]+)&amp;lt;.*UV RISK&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Name temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Name temperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Name windChill&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Name windChill_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Name windDirection&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15OExpr UConv::compasspoint2compasspoint($val,&amp;quot;en&amp;quot;,1,&amp;quot;de&amp;quot;)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Name windDirection_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Name windSpeed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Name windSpeed_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Name windGust&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Name windGust_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; sortby 03&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; stateFormat T: temperature °C | F: humidity % | W: windSpeed km/h | D: pressure hPa | U: solarUV | R: solarRadiation W/m²&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; timeout 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Diagramme ==&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
[[Bild:Plenticore_Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_2 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_2 SVG LogDB:SVG_LogDB_Photovoltaik_2:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_2.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-03-16 10:23:52&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Hauptverbraucher&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB PV_Anlage_1:Total_DC_Power:::$val=abs($val)&lt;br /&gt;
#LogDB PV_Anlage_1:Total_PV_Power_reserve::&lt;br /&gt;
#LogDB StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:::$val=abs($val)&lt;br /&gt;
#LogDB shelly02:Power_0::&lt;br /&gt;
#LogDB shelly03:Power::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC&#039; ls l1 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_PV_reserve&#039; ls l2 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Heizung&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Pool&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Waschmaschine&#039; ls l3 lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== RAW Definition Leistungsbezug ===&lt;br /&gt;
[[Bild:Plenticore_Leistungsbezug.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_3 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_3 SVG LogDB:SVG_LogDB_Photovoltaik_3:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_3.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-07-22 13:51:57&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Leistungsbezug&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
set yrange [0:9500]&lt;br /&gt;
set y2range [0:9500]&lt;br /&gt;
&lt;br /&gt;
#LogDB PV_Anlage_1:Total_DC_Power:::$val=abs($val)&lt;br /&gt;
#LogDB PV_Anlage_1:Home_own_consumption_from_PV::&lt;br /&gt;
#LogDB PV_Anlage_1:Home_own_consumption_from_battery::&lt;br /&gt;
#LogDB PV_Anlage_1:Home_own_consumption_from_grid::&lt;br /&gt;
#LogDB PV_Anlage_1:Actual_battery_charge_usable_Power::&lt;br /&gt;
#LogDB PV_Anlage_1:Total_DC_Power_Max::&lt;br /&gt;
#LogDB PV_Anlage_1:Battery_temperature:::$val=$val*100&lt;br /&gt;
#LogDB Heizung:heatSourceIN:::$val=$val*100&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Power&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;own_PV&#039; ls l2fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_use&#039; ls l0fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Grid_use&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_usable&#039; ls l4 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Max&#039; ls l6 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_Temp_Trend&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Out_Temp_Trend&#039; ls l2 lw 2 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== RAW Definition PV_Bilanz ===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_PV_Bilanz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Bilanz SVG LogDB:SVG_LogDB_PV_Bilanz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz alias SVG_LogDB_PV_Bilanz&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz fixedrange year&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Bilanz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-02 09:55:06&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Bilanz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB Dum.Energy:max_month_PVMonth::&lt;br /&gt;
#LogDB Dum.Energy:diff_week_PVMonth::&lt;br /&gt;
#LogDB Dum.Energy:diff_week_PVTotalMonth::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;PV-Bezug-Monat&#039; ls l2fill lw 2 with points,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;PV-Bezug-Woche&#039; ls l2fill lw 1 with fsteps,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;PV-Total-Woche&#039; ls l1fill lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RAW Definition Forecast / Calculation ===&lt;br /&gt;
[[Bild:Plenticore_Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_4 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_4 SVG LogDB:SVG_LogDB_Photovoltaik_4:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_4.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-17 08:58:42&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Forecast / Calculation&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set yrange [0:10000]&lt;br /&gt;
set y2range [0:10000]&lt;br /&gt;
&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=($val&amp;gt;0?$val*50+7000:7000)&lt;br /&gt;
#LogDB wetter_wolfskehlen_II:solarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_SolarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=7000&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_Calculation_fc1::&lt;br /&gt;
#LogDB PV_Anlage_1:Power_DC_Sum::&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_Calculation::&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_East::&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_South::&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_West::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Sonnenhöhe&#039; ls l7 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiation&#039; ls l8 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiationPrognose&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;70%&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation_fc1&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Power_DC_Sum&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;East&#039; ls l2 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;South&#039; ls l3 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;West&#039; ls l4 lw 0.5 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe ===&lt;br /&gt;
==== RAW Definition LWP_LuftWärmePumpe (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LWP dummy&lt;br /&gt;
attr LWP DbLogExclude .*&lt;br /&gt;
attr LWP DbLogInclude state&lt;br /&gt;
attr LWP alias LWP_LuftWärmePumpe&lt;br /&gt;
attr LWP group PV Eigenverbrauch&lt;br /&gt;
attr LWP icon sani_earth_source_heat_pump&lt;br /&gt;
attr LWP readingList LWP_Button PowerLevelMinTime PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr LWP room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP setList LWP_Button:uzsuToggle,on,off PowerLevelMinTime:slider,60,30,300 PowerLimitOn:slider,1000,250,4000 PowerLimitOff:slider,1000,250,4000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,900,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr LWP sortby 05&lt;br /&gt;
attr LWP stateFormat state&lt;br /&gt;
attr LWP verbose 0&lt;br /&gt;
attr LWP webCmd LWP_Button&lt;br /&gt;
&lt;br /&gt;
setstate LWP off&lt;br /&gt;
setstate LWP 2020-08-05 17:38:03 LWP_Button off&lt;br /&gt;
setstate LWP 2020-03-02 11:56:45 PowerLevelMinTime 600&lt;br /&gt;
setstate LWP 2020-02-05 14:11:42 PowerLimitOff 2250&lt;br /&gt;
setstate LWP 2020-03-02 11:56:39 PowerLimitOn 3000&lt;br /&gt;
setstate LWP 2019-08-02 10:31:21 RunTimeMin 3600&lt;br /&gt;
setstate LWP 2020-02-05 14:13:01 RunTimePerDay 28800&lt;br /&gt;
setstate LWP 2019-12-29 10:47:55 SetCmdOff set shelly01 off 0&lt;br /&gt;
setstate LWP 2019-07-22 15:35:59 SetCmdOn set shelly01 on 0&lt;br /&gt;
setstate LWP 2019-11-09 12:13:04 TimeEnd 16:00&lt;br /&gt;
setstate LWP 2020-04-02 13:51:54 TimeStart 12:30&lt;br /&gt;
setstate LWP 2020-08-05 17:38:03 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LWP_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
    ([LWP_Counter:pulseTimePerDay] &amp;gt;= [LWP:RunTimePerDay] and\&lt;br /&gt;
     [LWP_Counter:pulseTimeIncrement] &amp;gt;= [LWP:RunTimeMin] and\&lt;br /&gt;
     [LWP:state] ne &amp;quot;off&amp;quot; and [LWP:LWP_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot; LWP_PV cmd_1 PV : LWP off&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 50.0&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
  ( ([PV_Anlage_1:Total_PV_Power_reserve]+[StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung]) &amp;lt; [LWP:PowerLimitOff] and\&lt;br /&gt;
     [LWP_Counter:pulseTimeIncrement] &amp;gt;= [LWP:RunTimeMin] and\&lt;br /&gt;
     [LWP:state] ne &amp;quot;off&amp;quot; and\&lt;br /&gt;
     [LWP:LWP_Button] ne &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot; LWP_PV cmd_2 PV : LWP off&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 50.0&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außerkraft,\&lt;br /&gt;
##   wenn wärend der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [LWP:PowerLimitOff] and\&lt;br /&gt;
     [LWP_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
     [LWP_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
     [LWP:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_3 PV : Stop wait timer LWP&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([Astro:ObsSeason] ne &amp;quot;Sommer&amp;quot; and [Astro:ObsSeason] ne &amp;quot;Frühling&amp;quot; and\&lt;br /&gt;
     [PV_Anlage_1:Total_PV_Power_reserve] &amp;gt;= [LWP:PowerLimitOn] and\&lt;br /&gt;
     [[LWP:TimeStart]-[LWP:TimeEnd]] and\&lt;br /&gt;
     [LWP:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
     [LWP_Counter:pulseTimePerDay] &amp;lt; [LWP:RunTimePerDay] and\&lt;br /&gt;
     [Heizung:hotWaterTemperature] &amp;lt; 60 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_4 : LWP on&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP on&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 60.0&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Signal für den PV-Modus der LWP einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([LWP:LWP_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_5 PV : LWP on for manuel PV-Modus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP on&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 60.0&amp;quot;)}\&lt;br /&gt;
     )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Signal für den PV-Modus der LWP abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([LWP:LWP_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
     [$SELF:cmd_nr] eq &amp;quot;5&amp;quot;  )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_6 PV : LWP off after manuel PV-Modus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 50.0&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Stop wait Timer für das Abschalten, wenn die LWP beim Starten noch anläuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
   ([StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;gt; 300 and\&lt;br /&gt;
    [Heizung:opStateHeatPump1] eq &amp;quot;Wärmepumpe kommt&amp;quot; and\&lt;br /&gt;
    [Heizung:opStateHeatPump3] eq &amp;quot;Pumpenvorlauf&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
     ({Log 3, &amp;quot;LWP_PV cmd_7 : Stop wait timer LWP&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 LWP Ende\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
   ([StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;lt; 300 and\&lt;br /&gt;
    [LWP_Counter:pulseTimeIncrement] &amp;gt;= [LWP:RunTimeMin] and\&lt;br /&gt;
    ([Heizung:opStateHeatPump1] ne &amp;quot;Wärmepumpe läuft&amp;quot; or [Heizung:opStateHeatPump3] eq &amp;quot;Luftabtauen&amp;quot; ) and\&lt;br /&gt;
    ([$SELF:cmd_nr] eq &amp;quot;4&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;10&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_8 : LWP run finished&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 50.0&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading LWP LWP_Button off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 LWP Zwangseinschalten: Sollte das Brauchwasser noch nicht aufgeheizt sein, wird um die Hysterese erhöht.\&lt;br /&gt;
##   Dies kann passieren, wenn am Tag vorher der PV-Modus lief und dann das Wasser noch knapp über dem Mindestwert ist.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
   ([Astro:ObsSeason] ne &amp;quot;Sommer&amp;quot; and [Astro:ObsSeason] ne &amp;quot;Frühling&amp;quot; and\&lt;br /&gt;
    [[LWP:TimeEnd]] and\&lt;br /&gt;
    [Heizung:hotWaterTemperature] &amp;lt; 47 and\&lt;br /&gt;
    ([LWP_Counter:pulseTimePerDay] &amp;lt; [Pool:RunTimePerDay] or\&lt;br /&gt;
     [LWP_Counter:countsPerDay] eq 0) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_9 : LWP on for water heating&amp;quot;}\&lt;br /&gt;
\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget &amp;quot;. (ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperature&amp;quot;,46)+4))}\&lt;br /&gt;
\&lt;br /&gt;
     {Log 3, &amp;quot;LWP_PV cmd_9 : LWP hotWaterTemperatureTarget &amp;quot;.ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperatureTarget&amp;quot;,0)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 10 Hohe Priorität im Winter fuer die LWP\&lt;br /&gt;
##    Einschalten, wenn der Pool läuft, der Speicher geladen ist und noch Überschuss da ist.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([Astro:ObsSeason] eq &amp;quot;Winter&amp;quot; and\&lt;br /&gt;
     [PV_Anlage_1:Total_PV_Power_reserve] &amp;gt;= 2000 and\&lt;br /&gt;
     [shelly02:power_0] &amp;gt; 800 and\&lt;br /&gt;
     [PV_Anlage_1:Act_state_of_charge] &amp;gt; 60 and\&lt;br /&gt;
     [Heizung:hotWaterTemperature] &amp;lt; 60 and \&lt;br /&gt;
     [$SELF:cmd_nr] ne &amp;quot;10&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_10 : LWP Priorität&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP_PV cmd_4&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
&lt;br /&gt;
attr LWP_PV DbLogExclude .*&lt;br /&gt;
attr LWP_PV DbLogInclude state,cmd.*,Device,LWP_Status,wait_timer&lt;br /&gt;
attr LWP_PV alias LWP_PV&lt;br /&gt;
attr LWP_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch aus|Stop wait timer|Eigenverbrauch ein|LWP ein für manuellen PV-Modus|LWP aus nach manuellem PV-Modus|Stop wait timer fuer aus|LWP aus nach PV-Modus|LWP Brauchwasser nachheizen|LWP Priorität&lt;br /&gt;
attr LWP_PV do always&lt;br /&gt;
attr LWP_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_PV icon sani_earth_source_heat_pump&lt;br /&gt;
attr LWP_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_PV sortby 01&lt;br /&gt;
attr LWP_PV stateFormat state : LWP_Status : Brauchwasser e_Heizung_hotWaterTemperature °C&lt;br /&gt;
attr LWP_PV userReadings LWP_Status { ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;state&amp;quot;,&amp;quot;&amp;quot;) }&lt;br /&gt;
attr LWP_PV verbose 5&lt;br /&gt;
attr LWP_PV wait 0:10:0:[LWP:PowerLevelMinTime]:0:0:900:0:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- RAW Definition LWP_Signale (Shelly Modul: shelly1pm)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly01 Shelly 192.168.178.55&lt;br /&gt;
attr shelly01 DbLogExclude .*&lt;br /&gt;
attr shelly01 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly01 alias LWP_Signale&lt;br /&gt;
attr shelly01 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly01 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly01 icon taster_ch_1&lt;br /&gt;
attr shelly01 mode relay&lt;br /&gt;
attr shelly01 model shelly1pm&lt;br /&gt;
attr shelly01 room Shelly,Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly01 sortby 02&lt;br /&gt;
attr shelly01 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;power&amp;quot;,0),\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly01 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly01 webCmd |&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod LWP_Counter HourCounter LWP:on.* LWP:off&lt;br /&gt;
attr LWP_Counter DbLogExclude .*&lt;br /&gt;
attr LWP_Counter alias LWP_Counter&lt;br /&gt;
attr LWP_Counter event-min-interval .*:600&lt;br /&gt;
attr LWP_Counter event-on-change-reading .*&lt;br /&gt;
attr LWP_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_Counter icon time_timer&lt;br /&gt;
attr LWP_Counter interval 5&lt;br /&gt;
attr LWP_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_Counter sortby 03&lt;br /&gt;
attr LWP_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition rg_LWP_Status (readingsGroup Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod rg_LWP_Status readingsGroup &amp;lt;Device&amp;gt;,&amp;lt;Information&amp;gt;,&amp;lt;Wert&amp;gt; LWP:&amp;lt;Status&amp;gt;,state LWP:&amp;lt;PowerLevelMinTime&amp;gt;,PowerLevelMinTime LWP:&amp;lt;PowerLimitOn&amp;gt;,PowerLimitOn LWP:&amp;lt;PowerLimitOff&amp;gt;,PowerLimitOff LWP:&amp;lt;TimeStart&amp;gt;,!TimeStart LWP:&amp;lt;TimeEnd&amp;gt;,!TimeEnd LWP:&amp;lt;RunTimeMin&amp;gt;,RunTimeMin LWP_Counter:&amp;lt;RunTimeMin&amp;gt;,pulseTimeIncrement LWP:&amp;lt;RunTimePerDay&amp;gt;,RunTimePerDay LWP_Counter:&amp;lt;RunTimePerDay&amp;gt;,pulseTimePerDay LWP_PV:&amp;lt;wait&amp;gt;,wait_timer LWP_PV:&amp;lt;TimeStart&amp;gt;,timer_01_c04 LWP_PV:&amp;lt;TimeEnd&amp;gt;,timer_02_c04&lt;br /&gt;
attr rg_LWP_Status DbLogExclude .*&lt;br /&gt;
attr rg_LWP_Status alias Status LuftWärmePumpe Eigenverbrauch&lt;br /&gt;
attr rg_LWP_Status commands {state  =&amp;gt; &#039;state:on,off&#039;,\&lt;br /&gt;
PowerLevelMinTime =&amp;gt; &#039;PowerLevelMinTime:selectnumbers,60,60,600,0,lin&#039;,\&lt;br /&gt;
PowerLimitOn =&amp;gt; &#039;PowerLimitOn:selectnumbers,1000,250,4000,0,lin&#039;,\&lt;br /&gt;
PowerLimitOff =&amp;gt; &#039;PowerLimitOff:selectnumbers,1000,250,4000,0,lin&#039;,\&lt;br /&gt;
RunTimeMin =&amp;gt; &#039;RunTimeMin:selectnumbers,300,300,14400,0,lin&#039;,\&lt;br /&gt;
RunTimePerDay =&amp;gt; &#039;RunTimePerDay:selectnumbers,300,300,28800,0,lin&#039;,\&lt;br /&gt;
TimeStart =&amp;gt; &#039;TimeStart:time&#039;,\&lt;br /&gt;
TimeEnd =&amp;gt; &#039;TimeEnd:time&#039;}&lt;br /&gt;
attr rg_LWP_Status group PV Status&lt;br /&gt;
attr rg_LWP_Status nameStyle style=&amp;quot;color:grey&amp;quot;&lt;br /&gt;
attr rg_LWP_Status room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr rg_LWP_Status sortby 01&lt;br /&gt;
attr rg_LWP_Status style style=&amp;quot;font-size:18px&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool===&lt;br /&gt;
==== RAW Definition Pool_Softube (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool dummy&lt;br /&gt;
attr Pool DbLogExclude .*&lt;br /&gt;
attr Pool DbLogInclude state&lt;br /&gt;
attr Pool alias Pool_Softube&lt;br /&gt;
attr Pool event-on-change-reading .*&lt;br /&gt;
attr Pool group PV Eigenverbrauch&lt;br /&gt;
attr Pool icon scene_swimming&lt;br /&gt;
attr Pool readingList Pool_Button PowerLevelMinTime PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay RunTimePerDaySummer RunTimePerDayWinter SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Pool room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool setList Pool_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,500,100,1500 PowerLimitOff:slider,0,100,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,900,300,64800 RunTimePerDaySummer:slider,900,300,7200 RunTimePerDayWinter:slider,3600,900,64800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Pool sortby 06&lt;br /&gt;
attr Pool stateFormat state&lt;br /&gt;
attr Pool verbose 0&lt;br /&gt;
attr Pool webCmd Pool_Button&lt;br /&gt;
&lt;br /&gt;
setstate Pool off&lt;br /&gt;
setstate Pool 2020-08-28 13:30:10 Pool_Button off&lt;br /&gt;
setstate Pool 2019-12-02 10:31:26 PowerLevelMinTime 600&lt;br /&gt;
setstate Pool 2019-11-13 10:58:18 PowerLimitOff 800&lt;br /&gt;
setstate Pool 2019-11-06 11:49:00 PowerLimitOn 1000&lt;br /&gt;
setstate Pool 2020-08-14 16:26:09 RunTimeMin 1800&lt;br /&gt;
setstate Pool 2020-08-28 06:15:00 RunTimePerDay 3600&lt;br /&gt;
setstate Pool 2020-08-16 13:17:45 RunTimePerDaySummer 3600&lt;br /&gt;
setstate Pool 2020-08-25 19:32:33 RunTimePerDayWinter 14400&lt;br /&gt;
setstate Pool 2019-08-01 14:18:08 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool 2019-08-02 09:33:06 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool 2019-10-31 21:53:28 TimeEnd 16:00&lt;br /&gt;
setstate Pool 2020-04-08 18:19:29 TimeStart 12:30&lt;br /&gt;
setstate Pool 2020-08-28 14:13:02 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
 ([Pool_Counter:pulseTimePerDay] &amp;gt;= [Pool:RunTimePerDay] and\&lt;br /&gt;
  [Pool_Counter:pulseTimeIncrement] &amp;gt;= [Pool:RunTimeMin] and\&lt;br /&gt;
  [Pool:state] eq &amp;quot;on&amp;quot; and [Pool:Pool_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_1 : Pool off&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist.\&lt;br /&gt;
##   Bei Pool Nutzung und Pflegeprogramm wird nicht abgeschaltet.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Pool:PowerLimitOff] and\&lt;br /&gt;
  [Pool_Counter:pulseTimeIncrement] &amp;gt;= [Pool:RunTimeMin] and\&lt;br /&gt;
  [Pool:state] eq &amp;quot;on&amp;quot; and \&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;10&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_2 : Pool off&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Pool Pool_Button off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
##   wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Pool:PowerLimitOff] and\&lt;br /&gt;
  [$SELF:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [$SELF:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Pool:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_3 : Stop wait timer Pool&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch einschalten: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist wird\&lt;br /&gt;
##    und die Laufzeit pro Tag noch nicht erreicht ist;; Bei über 7000 Watt Einspeisung sofort aktivieren\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_Anlage_1:Total_PV_Power_reserve] &amp;gt;= [Pool:PowerLimitOn] and\&lt;br /&gt;
   [[Pool:TimeStart]-[Pool:TimeEnd]] and\&lt;br /&gt;
   [Pool:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
   [Pool_Counter:pulseTimePerDay] &amp;lt; [Pool:RunTimePerDay]\&lt;br /&gt;
  ) or\&lt;br /&gt;
  [PV_Anlage_1:Total_active_power_(powermeter)] &amp;lt;= -7000\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_4 : Pool on&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool on&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose für die Benutzung des Pools einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Pool:Pool_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_5 : Pool on for usage&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool on&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Pools abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Pool:Pool_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_6 : Pool off after usage&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Stop wait Timer für das Abschalten, wenn die Pumpe beim Starten noch anläuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly02:power_0] &amp;gt; 10 and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;9&amp;quot;) and\&lt;br /&gt;
  [$SELF:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [$SELF:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Pool:state] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_7 : Stop wait timer Pool&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly02:power_0] &amp;lt; 10 and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;9&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_8 : Pool run finished&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Pool Pool_Button off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Pool:TimeEnd]] and\&lt;br /&gt;
  ([Pool_Counter:pulseTimePerDay] &amp;lt; [Pool:RunTimePerDay] or\&lt;br /&gt;
   [Pool_Counter:countsPerDay] eq 0)\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_9 : Pool on for maintanance&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool on&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 10 Pflege Zwangseinschaltung bei günstigem Strom nachts im Winter\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Astro:ObsSeason] eq &amp;quot;Winter&amp;quot; and\&lt;br /&gt;
  [Strom_Kosten:aWATTar_Trigger] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [22:00-05:00]\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_10 : Pool on for maintanance by aWATTar&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool on&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 11 Abschaltung bei teurem Strom\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Astro:ObsSeason] eq &amp;quot;Winter&amp;quot; and\&lt;br /&gt;
  [Strom_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;10&amp;quot;\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_11 : Pool off after maintanance by aWATTar&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 12 Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([06:15] and [Heizung:averageAmbientTemperature])\&lt;br /&gt;
\&lt;br /&gt;
    (\&lt;br /&gt;
     { if ( [Heizung:averageAmbientTemperature] &amp;gt;= 18 )\&lt;br /&gt;
         {fhem(&amp;quot;setreading Pool RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;RunTimePerDaySummer&amp;quot;,0) )}\&lt;br /&gt;
      else \&lt;br /&gt;
         {fhem(&amp;quot;setreading Pool RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;RunTimePerDayWinter&amp;quot;,0) )}\&lt;br /&gt;
     },\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV cmd_12 : Pool RunTimePerDay switched&amp;quot;}\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
attr Pool_PV DbLogExclude .*&lt;br /&gt;
attr Pool_PV DbLogInclude cmd.*,state,cmd.*,Device,Pool_Pumpe_Status,wait_timer&lt;br /&gt;
attr Pool_PV alias Pool_PV&lt;br /&gt;
attr Pool_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch aus|Stop wait timer|Eigenverbrauch freigegeben|Pool ein für Benutzung|Pool aus nach Benutzung|Stop wait timer für aus|Pool aus|Pflegemodus ohne PV|Strombörse ein|Strombörse aus|RunTimePerDay switched&lt;br /&gt;
attr Pool_PV disable 0&lt;br /&gt;
attr Pool_PV do always&lt;br /&gt;
attr Pool_PV event-on-change-reading .*&lt;br /&gt;
attr Pool_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV icon scene_swimming&lt;br /&gt;
attr Pool_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV sortby 11&lt;br /&gt;
attr Pool_PV stateFormat state : Pool_Pumpe_Status&lt;br /&gt;
attr Pool_PV userReadings Pool_Pumpe_Status { ReadingsVal(&amp;quot;shelly02&amp;quot;,&amp;quot;power_0&amp;quot;,0)&amp;gt;10 ? &amp;quot;Pool_Pumpe_laeuft&amp;quot; : &amp;quot;Pool_Pumpe_aus&amp;quot;}&lt;br /&gt;
attr Pool_PV verbose 0&lt;br /&gt;
attr Pool_PV wait 0:10:0:[Pool:PowerLevelMinTime]:0:0:0:300:0:300&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool_Signale&lt;br /&gt;
attr shelly02 comment relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 12&lt;br /&gt;
attr shelly02 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly02 userReadings WebLink:network { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_Counter HourCounter shelly02:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly02:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Pool_Counter DbLogExclude .*&lt;br /&gt;
attr Pool_Counter alias Pool_Counter&lt;br /&gt;
attr Pool_Counter comment On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Pool_Counter event-on-change-reading .*&lt;br /&gt;
attr Pool_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_Counter icon time_timer&lt;br /&gt;
attr Pool_Counter interval 5&lt;br /&gt;
attr Pool_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_Counter sortby 13&lt;br /&gt;
attr Pool_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition rg_Pool_Status (readingsGroup Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod rg_Pool_Status readingsGroup &amp;lt;Device&amp;gt;,&amp;lt;Information&amp;gt;,&amp;lt;Wert&amp;gt; Pool:&amp;lt;Status&amp;gt;,!state Pool:&amp;lt;PowerLevelMinTime&amp;gt;,!PowerLevelMinTime Pool:&amp;lt;PowerLimitOn&amp;gt;,!PowerLimitOn Pool:&amp;lt;PowerLimitOff&amp;gt;,!PowerLimitOff Pool:&amp;lt;TimeStart&amp;gt;,!TimeStart Pool:&amp;lt;TimeEnd&amp;gt;,!TimeEnd Pool:&amp;lt;RunTimeMin&amp;gt;,!RunTimeMin Pool_Counter:&amp;lt;RunTimeMin&amp;gt;,!pulseTimeIncrement Pool:&amp;lt;RunTimePerDay&amp;gt;,!RunTimePerDay Pool:&amp;lt;RunTimePerDaySummer&amp;gt;,!RunTimePerDaySummer Pool:&amp;lt;RunTimePerDayWinter&amp;gt;,!RunTimePerDayWinter Pool_Counter:&amp;lt;RunTimePerDay&amp;gt;,!pulseTimePerDay Pool_PV:&amp;lt;wait&amp;gt;,wait_timer Pool_PV:&amp;lt;TimeStart&amp;gt;,timer_01_c04 Pool_PV:&amp;lt;TimeEnd&amp;gt;,timer_02_c04&lt;br /&gt;
attr rg_Pool_Status DbLogExclude .*&lt;br /&gt;
attr rg_Pool_Status alias Status Softube Pool Eigenverbrauch&lt;br /&gt;
attr rg_Pool_Status commands {state  =&amp;gt; &#039;state:on,off&#039;,\&lt;br /&gt;
PowerLevelMinTime =&amp;gt; &#039;PowerLevelMinTime:selectnumbers,60,30,600,0,lin&#039;,\&lt;br /&gt;
PowerLimitOn =&amp;gt; &#039;PowerLimitOn:selectnumbers,500,250,1500,0,lin&#039;,\&lt;br /&gt;
PowerLimitOff =&amp;gt; &#039;PowerLimitOff:selectnumbers,0,100,1000,0,lin&#039;,\&lt;br /&gt;
RunTimeMin =&amp;gt; &#039;RunTimeMin:selectnumbers,300,300,14400,0,lin&#039;,\&lt;br /&gt;
RunTimePerDaySummer =&amp;gt; &#039;RunTimePerDaySummer:selectnumbers,300,300,3600,0,lin&#039;,\&lt;br /&gt;
RunTimePerDayWinter =&amp;gt; &#039;RunTimePerDayWinter:selectnumbers,3600,900,64800,0,lin&#039;,\&lt;br /&gt;
TimeStart =&amp;gt; &#039;TimeStart:time&#039;,\&lt;br /&gt;
TimeEnd =&amp;gt; &#039;TimeEnd:time&#039;}&lt;br /&gt;
attr rg_Pool_Status group PV Status&lt;br /&gt;
attr rg_Pool_Status nameStyle style=&amp;quot;color:grey&amp;quot;&lt;br /&gt;
attr rg_Pool_Status room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr rg_Pool_Status sortby 02&lt;br /&gt;
attr rg_Pool_Status style style=&amp;quot;font-size:18px&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine dummy&lt;br /&gt;
attr Waschmaschine DbLogExclude .*&lt;br /&gt;
attr Waschmaschine DbLogInclude state&lt;br /&gt;
attr Waschmaschine alias Waschmaschine&lt;br /&gt;
attr Waschmaschine group PV Eigenverbrauch&lt;br /&gt;
attr Waschmaschine icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine readingList Waschmaschine_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Waschmaschine room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine setList Waschmaschine_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Waschmaschine sortby 07&lt;br /&gt;
attr Waschmaschine stateFormat state&lt;br /&gt;
attr Waschmaschine verbose 0&lt;br /&gt;
attr Waschmaschine webCmd Waschmaschine_Button&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine off&lt;br /&gt;
setstate Waschmaschine 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine 2019-11-06 10:56:22 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine 2020-04-20 13:06:04 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine 2019-12-02 15:01:18 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine 2020-04-02 13:59:34 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine 2020-01-01 16:29:10 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine 2020-01-01 16:29:24 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine 2019-08-01 14:25:25 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Waschmaschine 2020-08-27 16:17:23 Waschmaschine_Button off&lt;br /&gt;
setstate Waschmaschine 2020-08-28 16:29:42 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [Waschmaschine:RunTimePerDay] and\&lt;br /&gt;
  [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [Waschmaschine:RunTimeMin] and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;on&amp;quot; and [Waschmaschine:Waschmaschine_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Waschprogramm bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
## ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Waschmaschine:PowerLimitOff] and\&lt;br /&gt;
##  [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [Waschmaschine:RunTimeMin] and\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Waschmaschine:PowerLimitOn] and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Waschmaschine:PowerLimitOff] and\&lt;br /&gt;
  [Waschmaschine_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Waschmaschine_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_3 : Waschmaschine stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;gt; [Waschmaschine:PowerLimitOn] and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Waschmaschine:TimeStart]-[Waschmaschine:TimeEnd]] and\&lt;br /&gt;
  [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [Waschmaschine:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_4 : Waschmaschine freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung der Waschmaschine einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Waschmaschine:Waschmaschine_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_5 : Waschmaschine manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose der Waschmaschine manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Waschmaschine:Waschmaschine_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_6 : Waschmaschine manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly03:power] &amp;gt; 0 and\&lt;br /&gt;
  [shelly03:power_Waschmaschine_avg] &amp;lt; 70 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_7 : Waschmaschine Programm gestarted&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Waschprogramm gestartet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose beim Waschprogramm Ende\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly03:power] == 0 and\&lt;br /&gt;
  [shelly03:power_Waschmaschine_avg] &amp;gt; 0 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_8 : Waschmaschine aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine Waschmaschine_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Waschprogramm beendet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn die Waschmaschine nicht gebraucht wurde\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Waschmaschine:PowerLimitOn] and\&lt;br /&gt;
  [[Waschmaschine:TimeEnd]-[Waschmaschine:TimeStart]] and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine Waschmaschine_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Waschmaschine_PV DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV DbLogInclude state,STATE,cmd.*,Device,Waschmaschine_Status,wait_timer&lt;br /&gt;
attr Waschmaschine_PV alias Waschmaschine_PV&lt;br /&gt;
attr Waschmaschine_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Waschmaschine manuell ein|Waschmaschine manuell aus|Waschmaschine laeuft|Waschmaschine aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Waschmaschine_PV do always&lt;br /&gt;
attr Waschmaschine_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV sortby 21&lt;br /&gt;
attr Waschmaschine_PV stateFormat state : Waschmaschine_Status&lt;br /&gt;
attr Waschmaschine_PV verbose 0&lt;br /&gt;
attr Waschmaschine_PV wait 0:0:0:[Waschmaschine:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.54&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine_Signale&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 22&lt;br /&gt;
attr shelly03 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly03 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) },\&lt;br /&gt;
power_Waschmaschine_avg:power.* { movingAverage($NAME,&amp;quot;power&amp;quot;,300) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 23&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition rg_Waschmaschine_Status (readingsGroup Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod rg_Waschmaschine_Status readingsGroup &amp;lt;Device&amp;gt;,&amp;lt;Information&amp;gt;,&amp;lt;Wert&amp;gt; Waschmaschine:&amp;lt;Status&amp;gt;,!state Waschmaschine:&amp;lt;PowerLevelMinTime&amp;gt;,!PowerLevelMinTime Waschmaschine:&amp;lt;PowerLimitOn&amp;gt;,!PowerLimitOn Waschmaschine:&amp;lt;PowerLimitOff&amp;gt;,!PowerLimitOff Waschmaschine:&amp;lt;TimeStart&amp;gt;,!TimeStart Waschmaschine:&amp;lt;TimeEnd&amp;gt;,!TimeEnd Waschmaschine:&amp;lt;RunTimeMin&amp;gt;,!RunTimeMin Waschmaschine_Counter:&amp;lt;RunTimeMin&amp;gt;,!pulseTimeIncrement Waschmaschine:&amp;lt;RunTimePerDay&amp;gt;,!RunTimePerDay Waschmaschine_Counter:&amp;lt;RunTimePerDay&amp;gt;,!pulseTimePerDay Waschmaschine_PV:&amp;lt;wait&amp;gt;,wait_timer Waschmaschine_PV:&amp;lt;TimeStart&amp;gt;,timer_01_c04 Waschmaschine_PV:&amp;lt;TimeEnd&amp;gt;,timer_02_c04&lt;br /&gt;
attr rg_Waschmaschine_Status DbLogExclude .*&lt;br /&gt;
attr rg_Waschmaschine_Status alias Status Waschmaschine Eigenverbrauch&lt;br /&gt;
attr rg_Waschmaschine_Status commands {state  =&amp;gt; &#039;state:on,off&#039;,\&lt;br /&gt;
PowerLevelMinTime =&amp;gt; &#039;PowerLevelMinTime:selectnumbers,30,30,300,0,lin&#039;,\&lt;br /&gt;
PowerLimitOn =&amp;gt; &#039;PowerLimitOn:selectnumbers,250,250,2000,0,lin&#039;,\&lt;br /&gt;
PowerLimitOff =&amp;gt; &#039;PowerLimitOff:selectnumbers,0,50,800,0,lin&#039;,\&lt;br /&gt;
RunTimeMin =&amp;gt; &#039;RunTimeMin:selectnumbers,300,300,7200,0,lin&#039;,\&lt;br /&gt;
RunTimePerDay =&amp;gt; &#039;RunTimePerDay:selectnumbers,7200,300,28800,0,lin&#039;,\&lt;br /&gt;
TimeStart =&amp;gt; &#039;TimeStart:time&#039;,\&lt;br /&gt;
TimeEnd =&amp;gt; &#039;TimeEnd:time&#039;}&lt;br /&gt;
attr rg_Waschmaschine_Status group PV Status&lt;br /&gt;
attr rg_Waschmaschine_Status nameStyle style=&amp;quot;color:grey&amp;quot;&lt;br /&gt;
attr rg_Waschmaschine_Status room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr rg_Waschmaschine_Status sortby 03&lt;br /&gt;
attr rg_Waschmaschine_Status style style=&amp;quot;font-size:18px&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Other Components]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33938</id>
		<title>Benutzer:Plin53177</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33938"/>
		<updated>2020-09-16T06:51:23Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Server */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FHEM Landschaft (2020)==&lt;br /&gt;
[[Datei:Plin53177 landscape.PNG|rahmenlos|1261x1261px]]&lt;br /&gt;
&lt;br /&gt;
==FHEM-Instanzen==&lt;br /&gt;
===Main===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Hausmitte&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 3B&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic)&lt;br /&gt;
SIGNALduino (433 MHz, OOK)&lt;br /&gt;
|für Homematic-Devices&lt;br /&gt;
&lt;br /&gt;
für diverse Funkthermometer&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Zentrale Steuerung&lt;br /&gt;
Funkbasierte Steuerung&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|Alarm, CUL, CUL_HM, CUL_TCM97001, CUL_TX, DOIF, Dashboard, ESPEasy, FHEM2FHEM, FHEMWEB, FLAMINGO, FLOORPLAN, FileLog, HMLAN, HMinfo, HTTPSRV, HUEBridge, HUEDevice, HourCounter, IT, LEDStripe, LightScene, MSGMail, OREGON, PRESENCE, RESIDENTS, RFHEM, ROLLO, ROOMMATE, SD_WS, SD_WS07, SIGNALduino, SVG, SYSMON, THRESHOLD, TelegramBot, Text2Speech, Weather, WifiLight, at, autocreate, autoload_undefined_devices, cmdalias, define, devStateIcon, dummy, eventTypes, laststate, notify, readingsGroup, siri, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Server===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|x86-Server mit OpenSUSE Leap 15.1&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic) mit hmland&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|IP-basierte Module/Dienste&lt;br /&gt;
CUL-Verlängerung für Aktoren im Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|CALVIEW, CUL_HM, Calendar, DOIF, Dashboard, ESPEasy, FB_CALLLIST, FB_CALLMONITOR, FHEM2FHEM, FHEMWEB, FRITZBOX, FileLog, HTTPMOD, HTTPSRV, IPCAM, MPD, RFHEM, SIP, SIRD, STV, TelegramBot, Text2Speech, WOL, allowed, at, autocreate, autoload_undefined_devices, dummy, eventTypes, notify, onCreateEvent, plex, readingsGroup, telnet, vitoconnect, weblink&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Sonstiges&lt;br /&gt;
|collectd für Fritz!Box 7490, MariaDB für diverse Anwendungen&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Wohnzimmer===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Erdgeschoss&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|SIGNALduino (868 MHz, GFSK)&lt;br /&gt;
Lautsprecher&lt;br /&gt;
|für die Rolläden&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Rolladensteuerung&lt;br /&gt;
Sound-Ausgabe&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, FHEMWEB, FileLog, MsgQueue, PRESENCE, RFHEM, ROLLO, SD_Keeloq, SIGNALduino, Text2Speech, autocreate, autoload_undefined_devices, dummy, eventTypes, msgConfig, notify, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Log===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|docker container auf Server&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|(docker container)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|keine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Sammelt per FHEM2FHEM alle Metriken für die Visualisierung in Grafana&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, DockerImageInfo, FHEM, FHEM2FHEM, FHEMWEB, InfluxDBLog, RFHEM, dummy, eventTypes, notify, telnet&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
Wenn es bei der Speicherung von Daten in der InfluxDB zu IP-technischen Verzögerungen kommt, kann die gesamte FHEM-Instanz blockiert werden. Durch die Auslagerung in eine separate Instanz wird dies vermieden.&lt;br /&gt;
&lt;br /&gt;
==Visualisierung==&lt;br /&gt;
===Prometheus===&lt;br /&gt;
für die Sammlung von collectd-Zeitreihen, node_exporter etc.&lt;br /&gt;
===InfluxDB===&lt;br /&gt;
für die Sammlung von FHEM-Zeitreihen&lt;br /&gt;
===Grafana===&lt;br /&gt;
für die übergreifende Visualisierung von Zeitreihen&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Solar-/PV-%C3%9Cbersicht&amp;diff=33900</id>
		<title>Solar-/PV-Übersicht</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Solar-/PV-%C3%9Cbersicht&amp;diff=33900"/>
		<updated>2020-09-11T15:29:48Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Angrenzende Themen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;float:right;margin-left:10px&amp;quot;&amp;gt;__TOC__&amp;lt;/div&amp;gt;&lt;br /&gt;
Die Seite [[Solar-/PV-Übersicht]] soll einen schnellen Einstieg in die für Solar-/Photovoltaik-Betreiber relevanten Seiten und Threads ermöglichen. Bitte bei Bedarf selbständig ergänzen.&lt;br /&gt;
&lt;br /&gt;
==Forum==&lt;br /&gt;
Der Forenbereich {{Link2Forum|Area=Solaranlagen}} enthält Themen rund um Solaranlagen zur Wärme- oder Stromgewinnung&lt;br /&gt;
&lt;br /&gt;
== Allgemein ==&lt;br /&gt;
* [[Fotovoltaikanlage]]&lt;br /&gt;
* Viele Seiten der Kategorie [[:Kategorie:Energieerzeugungsmessung|Energieerzeugungsmessung]]&lt;br /&gt;
&lt;br /&gt;
==Wechselrichter==&lt;br /&gt;
===Kostal===&lt;br /&gt;
* [[KostalPiko]]&lt;br /&gt;
* [[Kostal Plenticore 10 Plus]]&lt;br /&gt;
&lt;br /&gt;
===SMA===&lt;br /&gt;
* [[SMAWechselrichter]]&lt;br /&gt;
&lt;br /&gt;
===Solar Edge===&lt;br /&gt;
* [[SolarEdge SE10k]]&lt;br /&gt;
&lt;br /&gt;
===Sunways===&lt;br /&gt;
* [[NT5000]]&lt;br /&gt;
&lt;br /&gt;
==Speicher==&lt;br /&gt;
* [[Sonnenspeicher]]&lt;br /&gt;
&lt;br /&gt;
==Monitoring/Auswertung==&lt;br /&gt;
* [[Enecsys Monitoring System]]&lt;br /&gt;
* [[SunnyHomeManager]]&lt;br /&gt;
* [[Datenbankgestützte Erstellung der Energiebilanz einer SMA PV-Anlage mit Überschusseinspeisung]]&lt;br /&gt;
* [[SolarLog]]&lt;br /&gt;
&lt;br /&gt;
==Angrenzende Themen==&lt;br /&gt;
Verwandte Themen, &amp;quot;gern verwendete&amp;quot; oder erforderliche Module, etc.:&lt;br /&gt;
* [[ModbusAttr]]&lt;br /&gt;
* [[SMLUSB]]&lt;br /&gt;
* Externer Link [https://www.photovoltaikforum.com/ Photovoltaik-Forum]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=33893</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=33893"/>
		<updated>2020-09-10T08:41:28Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* RAW Definition Wetter_ */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore 10 Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Python3]]&lt;br /&gt;
&amp;lt;!-- |ModOwner=  --&amp;gt;&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Bild:Plenticore FHEM 1.png|mini|900px|rechts|Die Diagramme im Überblick]]&lt;br /&gt;
[[Bild:Plenticore FHEM 2.png|mini|900px|rechts|Geräte Überblick mit manueller Schaltmöglichkeit]]&lt;br /&gt;
[[Bild:Plenticore FHEM 3.png|mini|900px|rechts|Steuerungsgeräte für die Schaltlogik]]&lt;br /&gt;
[[Bild:Plenticore FHEM 4.png|mini|900px|rechts|ReadingsGroup für die schnelle Parametereinstellung]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus]] [https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/ Hersteller Link] ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen Energietechnik ==&lt;br /&gt;
&lt;br /&gt;
Der Wechselrichter, der Speicher und der KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
== Geräte-Registrierung ==&lt;br /&gt;
&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
&lt;br /&gt;
== Hersteller Dokumentation ==&lt;br /&gt;
&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2018/06/15/11/40/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2018/04/12/08/26/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2018/04/12/08/26/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2019/03/12/07/13/kostal_update_plenticore_piko_iq_011504581.swu/ Plenticore Plus - Software Update UI: 01.15.04581 FW: 01.43]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2018/08/30/08/53/ba_kostal_interface_modbus-tcp_sunspec.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2019/03/06/13/17/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2019/03/06/13/17/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/06/09/11/49/kostal_update_ksem_1_2_1.zip/ KSEM - Software Update - 1.2.1]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2019/05/09/13/57/ba_kostal_interface_ksem---201911.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
== Einbindung in das Netzwerk ==&lt;br /&gt;
&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen FHEM Umfeld ==&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte müssen mit TCP/IP erreichbar sein ===&lt;br /&gt;
&lt;br /&gt;
=== Alle Module sollten auf einem aktuellen Stand sein ===&lt;br /&gt;
&lt;br /&gt;
=== Python ===&lt;br /&gt;
&lt;br /&gt;
==== Ein Python 3 sollte vorhanden sein ====&lt;br /&gt;
Wenn man die erweiterten Funktionalitäten, wie Statistiken, Speicher auslesen und später auch das Setzen von Werten im Plenticore, verwenden möchte.&lt;br /&gt;
&lt;br /&gt;
==== Es müssen folgende Python Module vorhanden sein ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
python3-pip&lt;br /&gt;
&lt;br /&gt;
pip3 install pycryptodome&lt;br /&gt;
pip3 install -U fhem&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Eine LogDB/LogDBRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird. ===&lt;br /&gt;
&lt;br /&gt;
=== Verwendete Module ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Modbus&lt;br /&gt;
- HTTPMOD&lt;br /&gt;
- expandJSON&lt;br /&gt;
- DbLog&lt;br /&gt;
- DbRep&lt;br /&gt;
- dummy&lt;br /&gt;
- Shelly&lt;br /&gt;
- HourCounter&lt;br /&gt;
- readingsGroup&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Einbindung in FHEM: Überblick ==&lt;br /&gt;
&lt;br /&gt;
=== Hardware Anbindung (alles über LAN) ===&lt;br /&gt;
&lt;br /&gt;
==== Kostal Plenticore Plus ====&lt;br /&gt;
===== Kostal Plenticore Plus die Basis information (Modbus/TCP) =====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
====== Plenticore Modbus Definition ======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Modbus Timing ======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
====== RAW Definition des konfigurations Dummy ======&lt;br /&gt;
Diese Dummy soll alle Konfigurationsparameter halten, auf die dann die anderen Geräte Definitionen zentral zugreifen. Hier können auch default Namen und Vorschläge für Werte in Form von Slidern und Auswahllisten hinterlegt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Anlage_1_config dummy&lt;br /&gt;
attr PV_Anlage_1_config DbLogExclude .*&lt;br /&gt;
attr PV_Anlage_1_config alias PV_Anlage_1_config&lt;br /&gt;
attr PV_Anlage_1_config comment Steht das reading module_*_count auf 0 wird diese Ausrichtung nicht berücksichtigt\&lt;br /&gt;
Passworte zu dieser Konfiguration liegen im Dateiverzeichnis ~./python/pwd_*.json\&lt;br /&gt;
\&lt;br /&gt;
Korrekturkurven:\&lt;br /&gt;
         Steilheit  Parallel\&lt;br /&gt;
                    verschiebung\&lt;br /&gt;
tempk      -0.39      25\&lt;br /&gt;
cloudk     -0.65       0\&lt;br /&gt;
raink      -0.30       0\&lt;br /&gt;
Der Slider für die Steilheit wird mit - k/100 umgerechnet. 39 ==&amp;gt; -0.39&lt;br /&gt;
attr PV_Anlage_1_config event-on-change-reading .*&lt;br /&gt;
attr PV_Anlage_1_config group PV Eigenverbrauch&lt;br /&gt;
attr PV_Anlage_1_config icon solar_icon&lt;br /&gt;
attr PV_Anlage_1_config readingList IP-Address_Plenticore IP-Address_BYD IP-Address_KSEM IP-Address_FHEM module_1_active module_2_active module_3_active module_1_name module_2_name module_3_name module_1_direction module_2_direction module_3_direction module_1_count module_2_count module_3_count module_1_power module_2_power module_3_power module_1_plain module_2_plain module_3_plain forecast_cloudk forecast_cloudk_base forecast_raink forecast_raink_base forecast_tempk forecast_tempk_base forecast_factor&lt;br /&gt;
attr PV_Anlage_1_config room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Anlage_1_config setList IP-Address_Plenticore IP-Address_BYD IP-Address_KSEM IP-Address_FHEM module_1_name:East,SouthEast,South,SouthWest,West module_2_name:East,SouthEast,South,SouthWest,West module_3_name:East,SouthEast,South,SouthWest,West module_1_direction:slider,-90,5,+90 module_2_direction:slider,-90,5,90 module_3_direction:slider,-90,5,90 module_1_count:slider,0,1,40 module_2_count:slider,0,1,40 module_3_count:slider,0,1,40 module_1_power:slider,250,10,400 module_2_power:slider,250,10,400 module_3_power:slider,250,10,400 module_1_plain:slider,15,1,45 module_2_plain:slider,15,1,45 module_3_plain:slider,15,1,45 forecast_cloudk:slider,0,1,100 forecast_cloudk_base:slider,0,1,10 forecast_raink:slider,0,1,100 forecast_raink_base:slider,0,1,10 forecast_tempk:slider,0,1,100 forecast_tempk_base:slider,10,1,30 forecast_factor:1,1.5,2,2.5,3,3.5,4,4.5,5&lt;br /&gt;
attr PV_Anlage_1_config sortby 06&lt;br /&gt;
attr PV_Anlage_1_config verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== RAW Definition des Wechselrichters ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Anlage_1 ModbusAttr 71 60 &amp;lt;IP-Address_Plenticore&amp;gt;:1502 TCP&lt;br /&gt;
attr PV_Anlage_1 DbLogExclude .*&lt;br /&gt;
attr PV_Anlage_1 DbLogInclude Act_state_of_charge,Actual_battery_charge_-minus_or_discharge_-plus_Power,Actual_battery_charge_usable_Power,Battery_temperature,Home_own_consumption_from_PV,Home_own_consumption_from_battery,Home_own_consumption_from_grid,Inverter_state,Power_DC1,Power_DC2,Power_DC_Sum,Total_DC_Power,Total_DC_Power_Max,Total_PV_Power_reserve,Voltage_DC1,Voltage_DC2,.*_yield,Solar_.*&lt;br /&gt;
attr PV_Anlage_1 alias PV_Einspeisung&lt;br /&gt;
attr PV_Anlage_1 comment Kostal Plenticore 10 Plus mit BYD Speicher&lt;br /&gt;
attr PV_Anlage_1 dev-h-defFormat %.2f&lt;br /&gt;
attr PV_Anlage_1 dev-h-defLen 2&lt;br /&gt;
attr PV_Anlage_1 dev-h-defPoll 1&lt;br /&gt;
attr PV_Anlage_1 dev-h-defRevRegs 1&lt;br /&gt;
attr PV_Anlage_1 dev-h-defUnpack f&amp;gt;&lt;br /&gt;
attr PV_Anlage_1 dev-type-STR-format %s&lt;br /&gt;
attr PV_Anlage_1 dev-type-STR-len 8&lt;br /&gt;
attr PV_Anlage_1 dev-type-STR-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 dev-type-STR-unpack a*&lt;br /&gt;
attr PV_Anlage_1 event-on-change-reading Act_state_of_charge,Actual_battery_charge_.*,Battery_temperature,Home_own_consumption_from_.*,Inverter_state,Power_DC1,Power_DC2,Power_DC_Sum,Total_DC_Power,Total_DC_Power_Max,Total_PV_Power_reserve,Voltage_DC1,Voltage_DC2,.*_yield,Solar_.*&lt;br /&gt;
attr PV_Anlage_1 group PV Eigenverbrauch&lt;br /&gt;
attr PV_Anlage_1 icon sani_solar&lt;br /&gt;
attr PV_Anlage_1 obj-h100-reading Total_DC_Power&lt;br /&gt;
attr PV_Anlage_1 obj-h104-format %s&lt;br /&gt;
attr PV_Anlage_1 obj-h104-reading State_of_energy_manager&lt;br /&gt;
attr PV_Anlage_1 obj-h104-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 obj-h104-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h106-reading Home_own_consumption_from_battery&lt;br /&gt;
attr PV_Anlage_1 obj-h108-reading Home_own_consumption_from_grid&lt;br /&gt;
attr PV_Anlage_1 obj-h110-reading Total_home_consumption_Battery&lt;br /&gt;
attr PV_Anlage_1 obj-h112-reading Total_home_consumption_Grid&lt;br /&gt;
attr PV_Anlage_1 obj-h114-reading Total_home_consumption_PV&lt;br /&gt;
attr PV_Anlage_1 obj-h116-reading Home_own_consumption_from_PV&lt;br /&gt;
attr PV_Anlage_1 obj-h118-reading Total_home_consumption&lt;br /&gt;
attr PV_Anlage_1 obj-h120-reading Isolation_resistance&lt;br /&gt;
attr PV_Anlage_1 obj-h122-reading Power_limit_from_EVU&lt;br /&gt;
attr PV_Anlage_1 obj-h124-reading Total_home_consumption_rate&lt;br /&gt;
attr PV_Anlage_1 obj-h14-reading Inverter_serial_number&lt;br /&gt;
attr PV_Anlage_1 obj-h14-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h144-reading Worktime&lt;br /&gt;
attr PV_Anlage_1 obj-h150-reading Actual_cos_phi&lt;br /&gt;
attr PV_Anlage_1 obj-h152-reading Grid_frequency&lt;br /&gt;
attr PV_Anlage_1 obj-h154-reading Current_Phase_1&lt;br /&gt;
attr PV_Anlage_1 obj-h156-reading Active_power_Phase_1&lt;br /&gt;
attr PV_Anlage_1 obj-h158-reading Voltage_Phase_1&lt;br /&gt;
attr PV_Anlage_1 obj-h160-reading Current_Phase_2&lt;br /&gt;
attr PV_Anlage_1 obj-h162-reading Active_power_Phase_2&lt;br /&gt;
attr PV_Anlage_1 obj-h164-reading Voltage_Phase_2&lt;br /&gt;
attr PV_Anlage_1 obj-h166-reading Current_Phase_3&lt;br /&gt;
attr PV_Anlage_1 obj-h168-reading Active_power_Phase_3&lt;br /&gt;
attr PV_Anlage_1 obj-h170-reading Voltage_Phase_3&lt;br /&gt;
attr PV_Anlage_1 obj-h172-reading Total_AC_active_power&lt;br /&gt;
attr PV_Anlage_1 obj-h174-reading Total_AC_reactive_power&lt;br /&gt;
attr PV_Anlage_1 obj-h178-reading Total_AC_apparent_power&lt;br /&gt;
attr PV_Anlage_1 obj-h190-reading Battery_charge_current&lt;br /&gt;
attr PV_Anlage_1 obj-h194-format %.0f&lt;br /&gt;
attr PV_Anlage_1 obj-h194-reading Number_of_battery_cycles&lt;br /&gt;
attr PV_Anlage_1 obj-h200-reading Actual_battery_charge_-minus_or_discharge_-plus_current&lt;br /&gt;
attr PV_Anlage_1 obj-h202-reading PSSB_fuse_state&lt;br /&gt;
attr PV_Anlage_1 obj-h208-format %.0f&lt;br /&gt;
attr PV_Anlage_1 obj-h208-reading Battery_ready_flag&lt;br /&gt;
attr PV_Anlage_1 obj-h210-reading Act_state_of_charge&lt;br /&gt;
attr PV_Anlage_1 obj-h212-reading Battery_state&lt;br /&gt;
attr PV_Anlage_1 obj-h214-reading Battery_temperature&lt;br /&gt;
attr PV_Anlage_1 obj-h216-reading Battery_voltage&lt;br /&gt;
attr PV_Anlage_1 obj-h218-reading Cos_phi_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h220-reading Frequency_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h222-reading Current_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h224-reading Active_power_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h226-reading Reactive_power_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h228-reading Apparent_power_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h230-reading Voltage_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h232-reading Current_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h234-reading Active_power_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h236-reading Reactive_power_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h238-reading Apparent_power_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h240-reading Voltage_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h242-reading Current_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h244-reading Active_power_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h246-reading Reactive_power_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h248-reading Apparent_power_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h250-reading Voltage_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h252-reading Total_active_power_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h254-reading Total_reactive_power_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h256-reading Total_apparent_power_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h258-reading Current_DC1&lt;br /&gt;
attr PV_Anlage_1 obj-h260-reading Power_DC1&lt;br /&gt;
attr PV_Anlage_1 obj-h266-reading Voltage_DC1&lt;br /&gt;
attr PV_Anlage_1 obj-h268-reading Current_DC2&lt;br /&gt;
attr PV_Anlage_1 obj-h270-reading Power_DC2&lt;br /&gt;
attr PV_Anlage_1 obj-h276-reading Voltage_DC2&lt;br /&gt;
attr PV_Anlage_1 obj-h278-reading Current_DC3&lt;br /&gt;
attr PV_Anlage_1 obj-h280-reading Power_DC3&lt;br /&gt;
attr PV_Anlage_1 obj-h286-reading Voltage_DC3&lt;br /&gt;
attr PV_Anlage_1 obj-h320-reading Total_yield&lt;br /&gt;
attr PV_Anlage_1 obj-h322-reading Daily_yield&lt;br /&gt;
attr PV_Anlage_1 obj-h324-reading Yearly_yield&lt;br /&gt;
attr PV_Anlage_1 obj-h326-reading Monthly_yield&lt;br /&gt;
attr PV_Anlage_1 obj-h38-reading Software-Version_Maincontroller_(MC)&lt;br /&gt;
attr PV_Anlage_1 obj-h38-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h384-len 16&lt;br /&gt;
attr PV_Anlage_1 obj-h384-reading Inverter_network_name&lt;br /&gt;
attr PV_Anlage_1 obj-h384-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h420-reading IP-address&lt;br /&gt;
attr PV_Anlage_1 obj-h420-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h428-reading IP-subnetmask&lt;br /&gt;
attr PV_Anlage_1 obj-h428-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h436-reading IP-gateway&lt;br /&gt;
attr PV_Anlage_1 obj-h436-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h446-reading IP-DNS1&lt;br /&gt;
attr PV_Anlage_1 obj-h446-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h454-reading IP-DNS2&lt;br /&gt;
attr PV_Anlage_1 obj-h454-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h46-reading Software-Version_IO-Controller_(IOC)&lt;br /&gt;
attr PV_Anlage_1 obj-h46-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h514-len 1&lt;br /&gt;
attr PV_Anlage_1 obj-h514-reading Battery_actual_SOC&lt;br /&gt;
attr PV_Anlage_1 obj-h517-reading Battery_Manufacturer&lt;br /&gt;
attr PV_Anlage_1 obj-h517-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h525-format %c&lt;br /&gt;
attr PV_Anlage_1 obj-h525-reading Battery_Model_ID&lt;br /&gt;
attr PV_Anlage_1 obj-h525-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h527-format %c&lt;br /&gt;
attr PV_Anlage_1 obj-h527-reading Battery_Serial_Number&lt;br /&gt;
attr PV_Anlage_1 obj-h529-len 4&lt;br /&gt;
attr PV_Anlage_1 obj-h529-reading Work_Capacity&lt;br /&gt;
attr PV_Anlage_1 obj-h529-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h531-format %.0f&lt;br /&gt;
attr PV_Anlage_1 obj-h531-reading Inverter_Max_Power&lt;br /&gt;
attr PV_Anlage_1 obj-h531-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h535-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 obj-h535-unpack n&lt;br /&gt;
attr PV_Anlage_1 obj-h551-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 obj-h559-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 obj-h56-format %.0f&lt;br /&gt;
attr PV_Anlage_1 obj-h56-reading Inverter_state&lt;br /&gt;
attr PV_Anlage_1 obj-h56-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h575-len 1&lt;br /&gt;
attr PV_Anlage_1 obj-h575-reading Inverter_Generation_Power_(actual)&lt;br /&gt;
attr PV_Anlage_1 obj-h577-len 2&lt;br /&gt;
attr PV_Anlage_1 obj-h577-reading Generation_Energy&lt;br /&gt;
attr PV_Anlage_1 obj-h577-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h578-reading Total_energy&lt;br /&gt;
attr PV_Anlage_1 obj-h582-reading Actual_battery_charge-discharge_power&lt;br /&gt;
attr PV_Anlage_1 obj-h586-format %s&lt;br /&gt;
attr PV_Anlage_1 obj-h586-reading Battery_Firmware&lt;br /&gt;
attr PV_Anlage_1 obj-h586-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h588-format %s&lt;br /&gt;
attr PV_Anlage_1 obj-h588-len 1&lt;br /&gt;
attr PV_Anlage_1 obj-h588-reading Battery_Type&lt;br /&gt;
attr PV_Anlage_1 obj-h588-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h6-reading Inverter_article_number&lt;br /&gt;
attr PV_Anlage_1 obj-h6-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h768-len 32&lt;br /&gt;
attr PV_Anlage_1 obj-h768-reading Productname&lt;br /&gt;
attr PV_Anlage_1 obj-h768-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h800-len 32&lt;br /&gt;
attr PV_Anlage_1 obj-h800-reading Power_class&lt;br /&gt;
attr PV_Anlage_1 obj-h800-type STR&lt;br /&gt;
attr PV_Anlage_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Anlage_1 sortby 01&lt;br /&gt;
attr PV_Anlage_1 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TH ALIGN=\&amp;quot;MIDDLE\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;Batterie %s&amp;lt;/TH&amp;gt;\&lt;br /&gt;
  &amp;lt;TH ALIGN=\&amp;quot;MIDDLE\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;aktuell&amp;lt;/TH&amp;gt;\&lt;br /&gt;
  &amp;lt;TH ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;Hausverbrauch&amp;lt;/TH&amp;gt;\&lt;br /&gt;
  &amp;lt;TH ALIGN=\&amp;quot;MIDDLE\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;Erträge&amp;lt;/TH&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD ALIGN=\&amp;quot;MIDDLE\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;\&lt;br /&gt;
    Leistung:  %04d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    Temp.: %02.1f °C&amp;lt;br&amp;gt;\&lt;br /&gt;
    Ladung total: %2d %%&amp;lt;br&amp;gt;\&lt;br /&gt;
    Ladung Res.: %04d Wh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;\&lt;br /&gt;
    DC total: %05d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    &amp;lt;br&amp;gt;\&lt;br /&gt;
    &amp;lt;br&amp;gt;\&lt;br /&gt;
    PV reserve: %05d W\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;\&lt;br /&gt;
    von PV: %05d W &amp;lt;br&amp;gt;\&lt;br /&gt;
    von Batterie: %05d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    vom Netz: %05d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    ins Haus: %05d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    Netz: %05d W\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;\&lt;br /&gt;
    Tag: %05d KWh &amp;lt;br&amp;gt;\&lt;br /&gt;
    Monat: %05d KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Jahr: %05d KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Total: %05d KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; , \&lt;br /&gt;
(ReadingsVal($name,&amp;quot;Actual_battery_charge_-minus_or_discharge_-plus_Power&amp;quot;,0) lt 0) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;Laden&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Entladen&amp;lt;/span&amp;gt;&amp;quot; ,\&lt;br /&gt;
\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Actual_battery_charge_-minus_or_discharge_-plus_Power&amp;quot;,0),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Battery_temperature&amp;quot;,0) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Act_state_of_charge&amp;quot;,0) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Actual_battery_charge_usable_Power&amp;quot;,0) ,\&lt;br /&gt;
\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Power_DC_Sum&amp;quot;,&amp;quot;0&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Total_PV_Power_reserve&amp;quot;,&amp;quot;0&amp;quot;),\&lt;br /&gt;
\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Home_own_consumption_from_PV&amp;quot;,0) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Home_own_consumption_from_battery&amp;quot;,0) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Home_own_consumption_from_grid&amp;quot;,0),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Home_own_consumption_from_PV&amp;quot;,0) +ReadingsVal($name,&amp;quot;Home_own_consumption_from_battery&amp;quot;,0)+ReadingsVal($name,&amp;quot;Home_own_consumption_from_grid&amp;quot;,0),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0),\&lt;br /&gt;
\&lt;br /&gt;
round(ReadingsVal($name,&amp;quot;Daily_yield&amp;quot;,0)/1000 ,0),\&lt;br /&gt;
round(ReadingsVal($name,&amp;quot;Monthly_yield&amp;quot;,0)/1000 ,0) ,\&lt;br /&gt;
round(ReadingsVal($name,&amp;quot;Yearly_yield&amp;quot;,0)/1000 ,0) ,\&lt;br /&gt;
round(ReadingsVal($name,&amp;quot;Total_yield&amp;quot;,0)/1000 ,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr PV_Anlage_1 userReadings Power_DC_Sum:Total_DC_Power.* { ReadingsVal($NAME,&amp;quot;Power_DC1&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal($NAME,&amp;quot;Power_DC2&amp;quot;,&amp;quot;0&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
Total_PV_Power_reserve:Total_DC_Power.* {my $reserve = ReadingsVal($NAME,&amp;quot;Power_DC_Sum&amp;quot;,&amp;quot;0&amp;quot;) * 0.90 - ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_PV&amp;quot;,&amp;quot;0&amp;quot;);;;; ($reserve lt 0)?0:round($reserve,3)  },\&lt;br /&gt;
\&lt;br /&gt;
Total_DC_Power_Max:Total_DC_Power.* { my $Bat_out = (ReadingsVal($NAME,&amp;quot;Actual_battery_charge_-minus_or_discharge_-plus_current&amp;quot;,&amp;quot;0&amp;quot;)*ReadingsVal($NAME,&amp;quot;Battery_voltage&amp;quot;,&amp;quot;0&amp;quot;));;;; ($Bat_out gt 0)?ReadingsVal($NAME,&amp;quot;Power_DC_Sum&amp;quot;,&amp;quot;0&amp;quot;) + $Bat_out :ReadingsVal($NAME,&amp;quot;Power_DC_Sum&amp;quot;,&amp;quot;0&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
Actual_battery_charge_-minus_or_discharge_-plus_Power:Actual_battery_charge_-minus_or_discharge_-plus_current.* {round((ReadingsVal($NAME,&amp;quot;Actual_battery_charge_-minus_or_discharge_-plus_current&amp;quot;,&amp;quot;0&amp;quot;)*ReadingsVal($NAME,&amp;quot;Battery_voltage&amp;quot;,&amp;quot;0&amp;quot;)),0)},\&lt;br /&gt;
\&lt;br /&gt;
Actual_battery_charge_usable_Power:Act_state_of_charge.* {my $x = (8960*(ReadingsVal($NAME,&amp;quot;Act_state_of_charge&amp;quot;,&amp;quot;0&amp;quot;)-10)/100);;;; ($x lt 0)?0:round($x,0) }&lt;br /&gt;
attr PV_Anlage_1 verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Userreadings ======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userreadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind. Dies betrifft insbesondere die Statistics_* readings, die durch ein Python Skript später erzeugt werden.&lt;br /&gt;
&lt;br /&gt;
Power_DC_Sum&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Dies berechnet direkt die Summe der DC-Leistung. Wenn der Plenticore einen Speicher hat, wird dieser am String 3 angeschlossen,&lt;br /&gt;
   sollte also kein Speicher vorhanden sein muss man hier den dritten String auch noch addieren.&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
&lt;br /&gt;
===== Kostal Plenticore Plus die API (über HTTPMOD mit Python Skript Authentifizierung) =====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Für diesen API Zugang über HTTP steht nun ein neues Gerät zur Verfügung, dass mit HTTPMOD und Python Authentifizierungsskripten die mehrstufige Anmeldung durchführt. Das ganze soll in Zukunft den starren Zugriff auf die Statistiken ablösen und eine Erweiterung zum setzen von Parametern im Plenticore bieten.&lt;br /&gt;
&lt;br /&gt;
====== Umstellungsaufwand, falls jemand früher eingestiegen ist. ======&lt;br /&gt;
Die erste Folge für den Umstieg ist, dass die Statistiken nicht mehr im PV_Anlage_1 Gerät abgelegt werden, da diese ja teil der API Abfrage sind. Das muss dann in der Bilanz berücksichtigt werden, da die Einträge dann unter dem neuen PV_Anlage_1_API Gerät abgelegt werden.&lt;br /&gt;
&lt;br /&gt;
2020.09.06 Die Umstellung auf das Plenticore API Gerät hat begonnen&lt;br /&gt;
&lt;br /&gt;
- Die Bilanz RAW Definition wurde aktualisiert&lt;br /&gt;
&lt;br /&gt;
- In der PV_Schedule Definition wurde das Kommando für die Aktualisierung der Statistik auf PV_Anlage_1_API umgestellt&lt;br /&gt;
&lt;br /&gt;
- Das Logging von Dum.Energy läuft wie gehabt weiter&lt;br /&gt;
&lt;br /&gt;
- Die Statistic_* readings aus dem PV_Anlage_1 Gerät können in der SQL Datenbank zum neuen PV_Anlage_1_API Gerät verschoben werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;SQL&amp;quot;&amp;gt;&lt;br /&gt;
## Bitte zuerst den Zeitraum, in dem die Statistikeinträge in die Datenbank geschrieben wurden feststellen.&lt;br /&gt;
MySQL [fhem]&amp;gt; SELECT TIMESTAMP,DEVICE,READING,VALUE FROM history WHERE DEVICE=&#039;PV_Anlage_1_API&#039; AND READING LIKE &#039;Statistic_%&#039; AND TIMESTAMP &amp;gt; &#039;2020-07-01 00:00:00&#039; ORDER BY TIMESTAMP LIMIT 500;&lt;br /&gt;
## Für den Update dann din Zeitraum so weit es geht einschränken, damit die Laufzeit in der Datenbank nicht so hoch wird.&lt;br /&gt;
MySQL [fhem]&amp;gt; UPDATE history SET TIMESTAMP=TIMESTAMP, DEVICE=&#039;PV_Anlage_1_API&#039; WHERE DEVICE=&#039;PV_Anlage_1&#039; AND READING LIKE &#039;Statistic_%&#039; AND TIMESTAMP &amp;gt; &#039;2020-07-01 00:00:00&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- Die alten Statistic_* readings können nun aus dem PV_Anlage_1 Gerät entfernt werden&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
deletereading PV_Anlage_1 Statistic_.*&lt;br /&gt;
deletereading PV_Anlage_1 statistics_.*&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- Für das Logging kann nun im Attribut &amp;quot;DbLogInclude&amp;quot; ebenfalls &amp;quot;Statistic_.*&amp;quot; entfernt werden&lt;br /&gt;
&lt;br /&gt;
- Beim Attribut &amp;quot;event-on-change-reading&amp;quot; sind auch &amp;quot;statistics_.*,Statistic_.*&amp;quot; zu entfernen&lt;br /&gt;
&lt;br /&gt;
- Das userreading im PV_Anlage_1 kann ebenfalls geändert werden und um diese Zeile verkürzt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
statistics_clean:statistics_output.* { my $x =  ReadingsVal($NAME,&amp;quot;statistics_output&amp;quot;,0);; $x =~ s/&amp;quot;moduleid&amp;quot;: &amp;quot;scb:statistic:EnergyFlow&amp;quot;, |, &amp;quot;moduleid&amp;quot;: &amp;quot;scb:statistic:EnergyFlow&amp;quot;|&amp;quot;processdata&amp;quot;: \[//g;; $x =~ s/id&amp;quot;: &amp;quot;|, &amp;quot;unit&amp;quot;: &amp;quot;&amp;quot;, &amp;quot;value&amp;quot;|^\[|\]\}\]$//g;; $x =~ s/moduleid/statistics_00_moduleid/g;; $x =~ s/processdata/statistics/g;; $x =~ s/\}\, \{/\, /g;; $x =~ s/\{\{/\{/g;; return $x }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- Nun noch das Gerät Plenticore_Statistics für das expandJSON löschen&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
delete Plenticore_Statistics&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Das sollten nun alle erforderlichen Bereinigungen für den Wechsel auf das PV_Anlage_1_API Gerät sein.&lt;br /&gt;
&lt;br /&gt;
====== Plenticore API ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Dateiverzeichnis ======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/fhem&lt;br /&gt;
/opt/fhem/python/pwd_fhem.json&lt;br /&gt;
/opt/fhem/python/pwd_plenticore.json&lt;br /&gt;
/opt/fhem/python/bin&lt;br /&gt;
/opt/fhem/python/bin/plenticore_auth_finish.py&lt;br /&gt;
/opt/fhem/python/bin/plenticore_auth_session.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Python 3 ======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ which python3&lt;br /&gt;
/usr/bin/python3&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ python3 --version&lt;br /&gt;
Python 3.7.3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Passworte ======&lt;br /&gt;
Die Passworte für den Plenticore und den FHEM Zugang liegen in einzelnen JSON Dateien&lt;br /&gt;
&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_plenticore.json&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;,&lt;br /&gt;
    &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Steht auf dem Gehäuse&amp;gt;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_fhem.json&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;username&amp;quot;: &amp;quot;&amp;lt;Ein Fhem Telnet User&amp;gt;&amp;quot;,&lt;br /&gt;
    &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Das Passwort des Users&amp;gt;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== plenticore_auth_* Erläuterung ======&lt;br /&gt;
Die folgenden beiden Skripte sind ein Extrakt aus den bisherigen Skripten, ohne die HTTP Aufrufe. Sie dienen nur noch der Generierung von Authentifizierungsschlüsseln. Optimaler Weise müssten sie auch noch nach Perl konvertiert werden, was für später geplant ist.&lt;br /&gt;
Als Übergabeparameter werden aus dem PV_Anlage_1_API Gerät Rückgabewerte der HTTP Aufrufe verwendet.&lt;br /&gt;
&lt;br /&gt;
====== plenticore_auth_finish ======&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ cat plenticore_auth_finish.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import string&lt;br /&gt;
import base64&lt;br /&gt;
import hashlib&lt;br /&gt;
import hmac&lt;br /&gt;
from Crypto.Cipher import AES&lt;br /&gt;
import binascii&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
import json&lt;br /&gt;
import fhem&lt;br /&gt;
&lt;br /&gt;
web          = sys.argv[1]&lt;br /&gt;
randomString = sys.argv[2]&lt;br /&gt;
nonce        = sys.argv[3]&lt;br /&gt;
salt         = sys.argv[4]&lt;br /&gt;
rounds       = sys.argv[5]&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_plenticore.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
PASSWD = credentials[&amp;quot;password&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
u       = randomString&lt;br /&gt;
&lt;br /&gt;
#u       = base64.b64encode(u.encode(&#039;utf-8&#039;)).decode(&#039;utf-8&#039;)&lt;br /&gt;
#print(&amp;quot;randomString: &amp;quot;,u)&lt;br /&gt;
&lt;br /&gt;
i       = nonce&lt;br /&gt;
o       = int(rounds)&lt;br /&gt;
a       = salt&lt;br /&gt;
bitSalt = base64.b64decode(a)&lt;br /&gt;
&lt;br /&gt;
#print(&amp;quot;nonce       : &amp;quot;,i)&lt;br /&gt;
#print(&amp;quot;salt        : &amp;quot;,a)&lt;br /&gt;
#print(&amp;quot;rounds      : &amp;quot;,o)&lt;br /&gt;
&lt;br /&gt;
def getPBKDF2Hash(password, bytedSalt, rounds):&lt;br /&gt;
    return hashlib.pbkdf2_hmac(&#039;sha256&#039;, password.encode(&#039;utf-8&#039;), bytedSalt, rounds)&lt;br /&gt;
&lt;br /&gt;
r = getPBKDF2Hash(PASSWD,bitSalt,o)&lt;br /&gt;
s = hmac.new(r, &amp;quot;Client Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
c = hmac.new(r, &amp;quot;Server Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
_ = hashlib.sha256(s).digest()&lt;br /&gt;
d = &amp;quot;n=user,r=&amp;quot;+u+&amp;quot;,r=&amp;quot;+i+&amp;quot;,s=&amp;quot;+a+&amp;quot;,i=&amp;quot;+str(o)+&amp;quot;,c=biws,r=&amp;quot;+i&lt;br /&gt;
g = hmac.new(_, d.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
p = hmac.new(c, d.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
f = bytes(a ^ b for (a, b) in zip(s, g))&lt;br /&gt;
proof = base64.b64encode(f).decode(&#039;utf-8&#039;)&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_fhem.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
fh = fhem.Fhem(web, protocol=&amp;quot;http&amp;quot;, port=8083, username=credentials[&amp;quot;username&amp;quot;], password=credentials[&amp;quot;password&amp;quot;])&lt;br /&gt;
&lt;br /&gt;
fh.send_cmd(&amp;quot;setreading PV_Anlage_1_API auth_proof &amp;quot; + proof)&lt;br /&gt;
&lt;br /&gt;
#print(&amp;quot;proof       : &amp;quot;,proof)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====== plenticore_auth_session ======&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ cat plenticore_auth_session.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import string&lt;br /&gt;
import base64&lt;br /&gt;
import hashlib&lt;br /&gt;
import os&lt;br /&gt;
import hmac&lt;br /&gt;
from Crypto.Cipher import AES&lt;br /&gt;
import binascii&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
import json&lt;br /&gt;
import fhem&lt;br /&gt;
&lt;br /&gt;
web          = sys.argv[1]&lt;br /&gt;
randomString = sys.argv[2]&lt;br /&gt;
nonce        = sys.argv[3]&lt;br /&gt;
salt         = sys.argv[4]&lt;br /&gt;
rounds       = sys.argv[5]&lt;br /&gt;
token        = sys.argv[6]&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_plenticore.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
PASSWD = credentials[&amp;quot;password&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
u       = randomString&lt;br /&gt;
i       = nonce&lt;br /&gt;
o       = int(rounds)&lt;br /&gt;
a       = salt&lt;br /&gt;
bitSalt = base64.b64decode(a)&lt;br /&gt;
&lt;br /&gt;
def getPBKDF2Hash(password, bytedSalt, rounds):&lt;br /&gt;
    return hashlib.pbkdf2_hmac(&#039;sha256&#039;, password.encode(&#039;utf-8&#039;), bytedSalt, rounds)&lt;br /&gt;
&lt;br /&gt;
r = getPBKDF2Hash(PASSWD,bitSalt,o)&lt;br /&gt;
&lt;br /&gt;
#print(&amp;quot;randomString: &amp;quot;,u)&lt;br /&gt;
#print(&amp;quot;nonce       : &amp;quot;,i)&lt;br /&gt;
#print(&amp;quot;salt        : &amp;quot;,a)&lt;br /&gt;
#print(&amp;quot;rounds      : &amp;quot;,o)&lt;br /&gt;
#print(&amp;quot;token       : &amp;quot;,token)&lt;br /&gt;
&lt;br /&gt;
s = hmac.new(r, &amp;quot;Client Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
_ = hashlib.sha256(s).digest()&lt;br /&gt;
d = &amp;quot;n=user,r=&amp;quot;+u+&amp;quot;,r=&amp;quot;+i+&amp;quot;,s=&amp;quot;+a+&amp;quot;,i=&amp;quot;+str(o)+&amp;quot;,c=biws,r=&amp;quot;+i&lt;br /&gt;
&lt;br /&gt;
y = hmac.new(_, &amp;quot;Session Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256)&lt;br /&gt;
y.update(d.encode(&#039;utf-8&#039;))&lt;br /&gt;
y.update(s)&lt;br /&gt;
P = y.digest()&lt;br /&gt;
protocol_key = P&lt;br /&gt;
t = os.urandom(16)&lt;br /&gt;
&lt;br /&gt;
e2          = AES.new(protocol_key,AES.MODE_GCM,t)&lt;br /&gt;
e2, authtag = e2.encrypt_and_digest(token.encode(&#039;utf-8&#039;))&lt;br /&gt;
&lt;br /&gt;
iv      = base64.b64encode(t).decode(&#039;utf-8&#039;)&lt;br /&gt;
authtag = base64.b64encode(authtag).decode(&amp;quot;utf-8&amp;quot;)&lt;br /&gt;
payload = base64.b64encode(e2).decode(&#039;utf-8&#039;)&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_fhem.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
fh = fhem.Fhem(web, protocol=&amp;quot;http&amp;quot;, port=8083, username=credentials[&amp;quot;username&amp;quot;], password=credentials[&amp;quot;password&amp;quot;])&lt;br /&gt;
&lt;br /&gt;
fh.send_cmd(&amp;quot;setreading PV_Anlage_1_API auth_iv &amp;quot; + iv)&lt;br /&gt;
fh.send_cmd(&amp;quot;setreading PV_Anlage_1_API auth_authtag &amp;quot; + authtag)&lt;br /&gt;
fh.send_cmd(&amp;quot;setreading PV_Anlage_1_API auth_payload &amp;quot; + payload)&lt;br /&gt;
&lt;br /&gt;
#print(&amp;quot;iv          : &amp;quot;,iv)&lt;br /&gt;
#print(&amp;quot;authtag     : &amp;quot;,authtag)&lt;br /&gt;
#print(&amp;quot;payload     : &amp;quot;,payload)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablaufbeschreibung PV_Anlage_1_API ======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit dem ersten Aufruf und läuft dann vollautomatisch bis zur Rückgabe der auth_sessionId&lt;br /&gt;
   1. get PV_Anlage_1_API 01/auth/start&lt;br /&gt;
* auth_randomString64 - wird generiert&lt;br /&gt;
* /api/v1/auth/start - HTTP request erfolgt&lt;br /&gt;
* auth_nonce, auth_salt, auth_rounds werden empfangen&lt;br /&gt;
   2. auth_Step1_Message:auth_nonce.* wird getriggert&lt;br /&gt;
* plenticore_auth_finish.py wird ausgeführt&lt;br /&gt;
* auth_proof - wird berechnet&lt;br /&gt;
   3. auth_Step2_Message:auth_proof.* wird getriggert&lt;br /&gt;
* Start von 02_/auth/finish&lt;br /&gt;
   4. get PV_Anlage_1_API 02_/auth/finish&lt;br /&gt;
* /api/v1/auth/finish - HTTP request erfolgt&lt;br /&gt;
* auth_signature, auth_token werden empfangen&lt;br /&gt;
   5. auth_Step3_Message:auth_token.* wird getriggert&lt;br /&gt;
* plenticore_auth_session.py wird ausgeführt&lt;br /&gt;
* auth_iv, auth_authtag, auth_payload - wird berechnet&lt;br /&gt;
   6. auth_Step4_Message:auth_payload.* wird getriggert&lt;br /&gt;
* Start von 03_/auth/session&lt;br /&gt;
   7. get PV_Anlage_1_API 03_/auth/session&lt;br /&gt;
* /api/v1/auth/session - HTTP request erfolgt&lt;br /&gt;
* auth_sessionId wird empfangen&lt;br /&gt;
&lt;br /&gt;
Bei allen folgenden HTTP requests wird nun die erhaltene auth_sessenId übermittelt.&lt;br /&gt;
&lt;br /&gt;
Bereits Implementierte Abfragen:&lt;br /&gt;
&lt;br /&gt;
get:&lt;br /&gt;
&lt;br /&gt;
start, finish, create_session werden für den Login benötigt und arbeiten über userreadings mit zwei Python Skripten zusammen&lt;br /&gt;
&lt;br /&gt;
01_/auth/start&lt;br /&gt;
&lt;br /&gt;
02_/auth/finish&lt;br /&gt;
&lt;br /&gt;
03_/auth/create_session&lt;br /&gt;
&lt;br /&gt;
Auskunft über den Anmeldezustand, es muss aber kurz vorher abgefragt werden&lt;br /&gt;
&lt;br /&gt;
04_/auth/me&lt;br /&gt;
&lt;br /&gt;
Informationen zum Plenticore&lt;br /&gt;
&lt;br /&gt;
05_/info/version&lt;br /&gt;
&lt;br /&gt;
Abfrage der Statistiken&lt;br /&gt;
&lt;br /&gt;
20_/processdata/scb_statistic_EnergyFlow&lt;br /&gt;
&lt;br /&gt;
Liste aller Plenticore Module. Es werden keine readings erzeugt. Das Ergebnis steht im httpbody, der mit attr &amp;lt;Device&amp;gt; showBody 1 angezeigt werden kann.&lt;br /&gt;
&lt;br /&gt;
21_/modules_list&lt;br /&gt;
&lt;br /&gt;
Hier gibt es viele technische Loggings. Sollte es Probleme beim Abholen der Daten geben kann es am timeout liegen&lt;br /&gt;
&lt;br /&gt;
24_/logdata/download&lt;br /&gt;
&lt;br /&gt;
Speicher Typen wurden folgende ermittelt 0=keine , 4=BYD&lt;br /&gt;
&lt;br /&gt;
Diese Abfragewerte können auch gesetzt werden, siehe set Befehle&lt;br /&gt;
&lt;br /&gt;
31_Battery_Type&lt;br /&gt;
&lt;br /&gt;
32_Battery_MinHomeComsumption&lt;br /&gt;
&lt;br /&gt;
33_Battery_Strategy&lt;br /&gt;
&lt;br /&gt;
34_Battery_MinSoc&lt;br /&gt;
&lt;br /&gt;
35_Battery_SmartBatteryControl_Enable&lt;br /&gt;
&lt;br /&gt;
36_Battery_DynamicSoc_Enable&lt;br /&gt;
&lt;br /&gt;
Das zeigt den FW Update Status beim FW Laden an. Die Rückmeldung ist im httpbody zu sehen, es werden keine readings erzeugt.&lt;br /&gt;
&lt;br /&gt;
41_/update/status&lt;br /&gt;
&lt;br /&gt;
set:&lt;br /&gt;
&lt;br /&gt;
Eine bestehende Session wird abgemeldet&lt;br /&gt;
&lt;br /&gt;
06_/auth/logout&lt;br /&gt;
&lt;br /&gt;
Die letzten Events können in deutsch oder englisch abgeholt werden&lt;br /&gt;
&lt;br /&gt;
23_/events/latest_5 [en-gb,de-de]&lt;br /&gt;
&lt;br /&gt;
Batterie Einstellungen können verändert werden. Es werden einige Werte vorgeschlagen. Bitte vorher immer den aktuellen Wert abfragen und besser aufschreiben!&lt;br /&gt;
&lt;br /&gt;
Hier sollte nur etwas gesetzt werden, wenn man sich sicher ist, was man tut.&lt;br /&gt;
&lt;br /&gt;
31_Battery_Type [0,4]&lt;br /&gt;
&lt;br /&gt;
32_Battery_MinHomeComsumption&lt;br /&gt;
&lt;br /&gt;
33_Battery_Strategy&lt;br /&gt;
&lt;br /&gt;
34_Battery_MinSoc&lt;br /&gt;
&lt;br /&gt;
35_Battery_SmartBatteryControl_Enable&lt;br /&gt;
&lt;br /&gt;
36_Battery_DynamicSoc_Enable&lt;br /&gt;
&lt;br /&gt;
Der Reboot läuft noch nicht. Da ist die API ziemlich zickig. Ich habe jedoch bereits ein Skript, womit es geht :-)&lt;br /&gt;
&lt;br /&gt;
51_/system/reboot&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch eine Login mit Sessionaufbau durchgeführt.&lt;br /&gt;
&lt;br /&gt;
====== RAW Definition des PV_Anlage_1_API ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Anlage_1_API HTTPMOD http://%IP-Address_Plenticore%/api/v1/auth/me 0&lt;br /&gt;
&lt;br /&gt;
attr PV_Anlage_1_API DbLogExclude .*&lt;br /&gt;
attr PV_Anlage_1_API DbLogInclude Statistic_.*&lt;br /&gt;
attr PV_Anlage_1_API authRetries 1&lt;br /&gt;
attr PV_Anlage_1_API dontRequeueAfterAuth 1&lt;br /&gt;
attr PV_Anlage_1_API enableControlSet 0&lt;br /&gt;
attr PV_Anlage_1_API enableCookies 1&lt;br /&gt;
attr PV_Anlage_1_API get01Data {&amp;quot;nonce&amp;quot;: &amp;quot;%randomString64%&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API get01Name 01_/auth/start&lt;br /&gt;
attr PV_Anlage_1_API get01URL http://%IP-Address_Plenticore%/api/v1/auth/start&lt;br /&gt;
attr PV_Anlage_1_API get02-1Name auth_signature&lt;br /&gt;
attr PV_Anlage_1_API get02-2Name auth_token&lt;br /&gt;
attr PV_Anlage_1_API get02Data {&amp;quot;transactionId&amp;quot;: &amp;quot;%auth_transactionId%&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;%auth_proof%&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API get02JSON .&lt;br /&gt;
attr PV_Anlage_1_API get02Name 02_/auth/finish&lt;br /&gt;
attr PV_Anlage_1_API get02URL http://%IP-Address_Plenticore%/api/v1/auth/finish&lt;br /&gt;
attr PV_Anlage_1_API get03Data {&amp;quot;transactionId&amp;quot;: &amp;quot;%auth_transactionId%&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;%auth_iv%&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;%auth_authtag%&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;%auth_payload%&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API get03Name 03_/auth/create_session&lt;br /&gt;
attr PV_Anlage_1_API get03URL http://%IP-Address_Plenticore%/api/v1/auth/create_session&lt;br /&gt;
attr PV_Anlage_1_API get04-1Name auth_me_active&lt;br /&gt;
attr PV_Anlage_1_API get04-2Name auth_me_locked&lt;br /&gt;
attr PV_Anlage_1_API get04-3Name auth_me_authenticated&lt;br /&gt;
attr PV_Anlage_1_API get04-4Name auth_me_anonymous&lt;br /&gt;
attr PV_Anlage_1_API get04-5Name auth_me_role&lt;br /&gt;
attr PV_Anlage_1_API get04-6Name auth_me_permissions&lt;br /&gt;
attr PV_Anlage_1_API get04Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get04JSON .&lt;br /&gt;
attr PV_Anlage_1_API get04Name 04_/auth/me&lt;br /&gt;
attr PV_Anlage_1_API get04URL http://%IP-Address_Plenticore%/api/v1/auth/me&lt;br /&gt;
attr PV_Anlage_1_API get05-1Name info_name&lt;br /&gt;
attr PV_Anlage_1_API get05-2Name info_api_version&lt;br /&gt;
attr PV_Anlage_1_API get05-3Name info_sw_version&lt;br /&gt;
attr PV_Anlage_1_API get05-4Name info_hostname&lt;br /&gt;
attr PV_Anlage_1_API get05JSON .&lt;br /&gt;
attr PV_Anlage_1_API get05Name 05_/info/version&lt;br /&gt;
attr PV_Anlage_1_API get05URL http://%IP-Address_Plenticore%/api/v1/info/version&lt;br /&gt;
attr PV_Anlage_1_API get20-10Name Statistic_EnergyHome_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-11Name Statistic_EnergyHome_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-12Name Statistic_EnergyHome_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-13Name Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-14Name Statistic_EnergyHomeBat_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-15Name Statistic_EnergyHomeBat_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-16Name Statistic_EnergyHomeBat_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-17Name Statistic_EnergyHomeGrid_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-18Name Statistic_EnergyHomeGrid_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-19Name Statistic_EnergyHomeGrid_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-1Name Statistic_Autarky_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-20Name Statistic_EnergyHomeGrid_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-21Name Statistic_EnergyHomePv_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-22Name Statistic_EnergyHomePv_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-23Name Statistic_EnergyHomePv_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-24Name Statistic_EnergyHomePv_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-25Name Statistic_OwnConsumptionRate_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-26Name Statistic_OwnConsumptionRate_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-27Name Statistic_OwnConsumptionRate_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-28Name Statistic_OwnConsumptionRate_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-29Name Statistic_Yield_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-2Name Statistic_Autarky_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-30Name Statistic_Yield_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-31Name Statistic_Yield_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-32Name Statistic_Yield_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-3Name Statistic_Autarky_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-4Name Statistic_Autarky_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-5Name Statistic_CO2Saving_Day&lt;br /&gt;
attr PV_Anlage_1_API get20-6Name Statistic_CO2Saving_Month&lt;br /&gt;
attr PV_Anlage_1_API get20-7Name Statistic_CO2Saving_Total&lt;br /&gt;
attr PV_Anlage_1_API get20-8Name Statistic_CO2Saving_Year&lt;br /&gt;
attr PV_Anlage_1_API get20-9Name Statistic_EnergyHome_Day&lt;br /&gt;
attr PV_Anlage_1_API get20Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get20JSON 01_processdata_.._value&lt;br /&gt;
attr PV_Anlage_1_API get20Name 20_/processdata/scb_statistic_EnergyFlow&lt;br /&gt;
attr PV_Anlage_1_API get20URL http://%IP-Address_Plenticore%/api/v1/processdata/scb:statistic:EnergyFlow&lt;br /&gt;
attr PV_Anlage_1_API get21Name 21_/modules_list&lt;br /&gt;
attr PV_Anlage_1_API get21URL http://%IP-Address_Plenticore%/api/v1/modules&lt;br /&gt;
attr PV_Anlage_1_API get24Data {&amp;quot;end&amp;quot;:&amp;quot;%end_date%&amp;quot;,&amp;quot;begin&amp;quot;:&amp;quot;%begin_date%&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API get24Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get24Header02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get24Name 24_/logdata/download&lt;br /&gt;
attr PV_Anlage_1_API get24URL http://%IP-Address_Plenticore%/api/v1/logdata/download&lt;br /&gt;
attr PV_Anlage_1_API get31-1Name Battery_Type&lt;br /&gt;
attr PV_Anlage_1_API get31-2Name Battery_Type&lt;br /&gt;
attr PV_Anlage_1_API get31Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get31Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get31JSON .&lt;br /&gt;
attr PV_Anlage_1_API get31Name 31_Battery_Type&lt;br /&gt;
attr PV_Anlage_1_API get31URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:Type&lt;br /&gt;
attr PV_Anlage_1_API get32-1Name Battery_MinHomeComsumption&lt;br /&gt;
attr PV_Anlage_1_API get32-2Name Battery_MinHomeComsumption&lt;br /&gt;
attr PV_Anlage_1_API get32Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get32Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get32JSON .&lt;br /&gt;
attr PV_Anlage_1_API get32Name 32_Battery_MinHomeComsumption&lt;br /&gt;
attr PV_Anlage_1_API get32URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:MinHomeComsumption&lt;br /&gt;
attr PV_Anlage_1_API get33-1Name Battery_Strategy&lt;br /&gt;
attr PV_Anlage_1_API get33-2Name Battery_Strategy&lt;br /&gt;
attr PV_Anlage_1_API get33Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get33Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get33JSON .&lt;br /&gt;
attr PV_Anlage_1_API get33Name 33_Battery_Strategy&lt;br /&gt;
attr PV_Anlage_1_API get33URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:Strategy&lt;br /&gt;
attr PV_Anlage_1_API get34-1Name Battery_MinSoc&lt;br /&gt;
attr PV_Anlage_1_API get34-2Name Battery_MinSoc&lt;br /&gt;
attr PV_Anlage_1_API get34Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get34Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get34JSON .&lt;br /&gt;
attr PV_Anlage_1_API get34Name 34_Battery_MinSoc&lt;br /&gt;
attr PV_Anlage_1_API get34URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:MinSoc&lt;br /&gt;
attr PV_Anlage_1_API get35-1Name Battery_SmartBatteryControl_Enable&lt;br /&gt;
attr PV_Anlage_1_API get35-2Name Battery_SmartBatteryControl_Enable&lt;br /&gt;
attr PV_Anlage_1_API get35Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get35Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get35JSON .&lt;br /&gt;
attr PV_Anlage_1_API get35Name 35_Battery_SmartBatteryControl_Enable&lt;br /&gt;
attr PV_Anlage_1_API get35URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:SmartBatteryControl:Enable&lt;br /&gt;
attr PV_Anlage_1_API get36-1Name Battery_DynamicSoc_Enable&lt;br /&gt;
attr PV_Anlage_1_API get36-2Name Battery_DynamicSoc_Enable&lt;br /&gt;
attr PV_Anlage_1_API get36Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get36Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API get36JSON .&lt;br /&gt;
attr PV_Anlage_1_API get36Name 36_Battery_DynamicSoc_Enable&lt;br /&gt;
attr PV_Anlage_1_API get36URL http://%IP-Address_Plenticore%/api/v1/settings/devices:local/Battery:DynamicSoc:Enable&lt;br /&gt;
attr PV_Anlage_1_API get41Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get41Name 41_/update/status&lt;br /&gt;
attr PV_Anlage_1_API get41URL http://%IP-Address_Plenticore%/api/v1/update/status&lt;br /&gt;
attr PV_Anlage_1_API getHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr PV_Anlage_1_API getHeader02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API group PV Eigenverbrauch&lt;br /&gt;
attr PV_Anlage_1_API icon sani_solar&lt;br /&gt;
attr PV_Anlage_1_API reAuthRegex &amp;quot;authenticated&amp;quot;:false|&amp;quot;processdata&amp;quot;:\[\]|wrong credentials&lt;br /&gt;
attr PV_Anlage_1_API reading01-1Name auth_nonce&lt;br /&gt;
attr PV_Anlage_1_API reading01-2Name auth_rounds&lt;br /&gt;
attr PV_Anlage_1_API reading01-3Name auth_salt&lt;br /&gt;
attr PV_Anlage_1_API reading01-4Name auth_transactionId&lt;br /&gt;
attr PV_Anlage_1_API reading01JSON .&lt;br /&gt;
attr PV_Anlage_1_API reading02JSON sessionId&lt;br /&gt;
attr PV_Anlage_1_API reading02Name auth_sessionId&lt;br /&gt;
attr PV_Anlage_1_API reading0301JSON message&lt;br /&gt;
attr PV_Anlage_1_API reading0301Name info_message&lt;br /&gt;
attr PV_Anlage_1_API reading0302JSON error&lt;br /&gt;
attr PV_Anlage_1_API reading0302Name info_error&lt;br /&gt;
attr PV_Anlage_1_API replacement01Mode expression&lt;br /&gt;
attr PV_Anlage_1_API replacement01Regex %IP-Address_Plenticore%&lt;br /&gt;
attr PV_Anlage_1_API replacement01Value {ReadingsVal(&amp;quot;PV_Anlage_1_config&amp;quot;,&amp;quot;IP-Address_Plenticore&amp;quot;,&amp;quot;&amp;quot;)}&lt;br /&gt;
attr PV_Anlage_1_API replacement02Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement02Regex %auth_transactionId%&lt;br /&gt;
attr PV_Anlage_1_API replacement02Value auth_transactionId&lt;br /&gt;
attr PV_Anlage_1_API replacement03Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement03Regex %auth_proof%&lt;br /&gt;
attr PV_Anlage_1_API replacement03Value auth_proof&lt;br /&gt;
attr PV_Anlage_1_API replacement04Mode expression&lt;br /&gt;
attr PV_Anlage_1_API replacement04Regex %randomString64%&lt;br /&gt;
attr PV_Anlage_1_API replacement04Value {my $NAME = &amp;quot;PV_Anlage_1_API&amp;quot; ;;;;fhem(&amp;quot;deletereading &amp;quot;.$NAME.&amp;quot; message&amp;quot;);;;;fhem(&amp;quot;deletereading &amp;quot;.$NAME.&amp;quot; auth.*&amp;quot;);;;;my @chars=(&#039;a&#039;..&#039;z&#039;,&#039;A&#039;..&#039;Z&#039;,&#039;0&#039;..&#039;9&#039;);; my $r;; foreach(1..16) {$r.=$chars[rand @chars];;};;;; fhem(&amp;quot;setreading &amp;quot;.$NAME.&amp;quot; auth_randomString64 &amp;quot;.$r);;;; $r;;;;}&lt;br /&gt;
attr PV_Anlage_1_API replacement05Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement05Regex %auth_randomString64%&lt;br /&gt;
attr PV_Anlage_1_API replacement05Value auth_randomString64&lt;br /&gt;
attr PV_Anlage_1_API replacement06Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement06Regex %auth_token%&lt;br /&gt;
attr PV_Anlage_1_API replacement06Value auth_token&lt;br /&gt;
attr PV_Anlage_1_API replacement07Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement07Regex %auth_signature%&lt;br /&gt;
attr PV_Anlage_1_API replacement07Value auth_signature&lt;br /&gt;
attr PV_Anlage_1_API replacement08Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement08Regex %auth_authtag%&lt;br /&gt;
attr PV_Anlage_1_API replacement08Value auth_authtag&lt;br /&gt;
attr PV_Anlage_1_API replacement09Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement09Regex %auth_payload%&lt;br /&gt;
attr PV_Anlage_1_API replacement09Value auth_payload&lt;br /&gt;
attr PV_Anlage_1_API replacement10Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement10Regex %auth_iv%&lt;br /&gt;
attr PV_Anlage_1_API replacement10Value auth_iv&lt;br /&gt;
attr PV_Anlage_1_API replacement11Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement11Regex %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API replacement11Value auth_sessionId&lt;br /&gt;
attr PV_Anlage_1_API replacement12Mode expression&lt;br /&gt;
attr PV_Anlage_1_API replacement12Regex %begin_date%&lt;br /&gt;
attr PV_Anlage_1_API replacement12Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr PV_Anlage_1_API replacement13Mode expression&lt;br /&gt;
attr PV_Anlage_1_API replacement13Regex %end_date%&lt;br /&gt;
attr PV_Anlage_1_API replacement13Value {POSIX::strftime(&amp;quot;%Y-%m-%d&amp;quot;,localtime(time))}&lt;br /&gt;
attr PV_Anlage_1_API room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Anlage_1_API set06Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set06Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set06Method POST&lt;br /&gt;
attr PV_Anlage_1_API set06Name 06_/auth/logout&lt;br /&gt;
attr PV_Anlage_1_API set06NoArg 1&lt;br /&gt;
attr PV_Anlage_1_API set06URL http://%IP-Address_Plenticore%/api/v1/auth/logout&lt;br /&gt;
attr PV_Anlage_1_API set23-10Name Event_02_code&lt;br /&gt;
attr PV_Anlage_1_API set23-11Name Event_02_description&lt;br /&gt;
attr PV_Anlage_1_API set23-12Name Event_02_end_time&lt;br /&gt;
attr PV_Anlage_1_API set23-13Name Event_02_group&lt;br /&gt;
attr PV_Anlage_1_API set23-14Name Event_02_is_active&lt;br /&gt;
attr PV_Anlage_1_API set23-15Name Event_02_long_description&lt;br /&gt;
attr PV_Anlage_1_API set23-16Name Event_02_start_time&lt;br /&gt;
attr PV_Anlage_1_API set23-17Name Event_03_category&lt;br /&gt;
attr PV_Anlage_1_API set23-18Name Event_03_code&lt;br /&gt;
attr PV_Anlage_1_API set23-19Name Event_03_description&lt;br /&gt;
attr PV_Anlage_1_API set23-1Name Event_01_category&lt;br /&gt;
attr PV_Anlage_1_API set23-20Name Event_03_end_time&lt;br /&gt;
attr PV_Anlage_1_API set23-21Name Event_03_group&lt;br /&gt;
attr PV_Anlage_1_API set23-22Name Event_03_is_active&lt;br /&gt;
attr PV_Anlage_1_API set23-23Name Event_03_long_description&lt;br /&gt;
attr PV_Anlage_1_API set23-24Name Event_03_start_time&lt;br /&gt;
attr PV_Anlage_1_API set23-25Name Event_04_category&lt;br /&gt;
attr PV_Anlage_1_API set23-26Name Event_04_code&lt;br /&gt;
attr PV_Anlage_1_API set23-27Name Event_04_description&lt;br /&gt;
attr PV_Anlage_1_API set23-28Name Event_04_end_time&lt;br /&gt;
attr PV_Anlage_1_API set23-29Name Event_04_group&lt;br /&gt;
attr PV_Anlage_1_API set23-2Name Event_01_code&lt;br /&gt;
attr PV_Anlage_1_API set23-30Name Event_04_is_active&lt;br /&gt;
attr PV_Anlage_1_API set23-31Name Event_04_long_description&lt;br /&gt;
attr PV_Anlage_1_API set23-32Name Event_04_start_time&lt;br /&gt;
attr PV_Anlage_1_API set23-33Name Event_05_category&lt;br /&gt;
attr PV_Anlage_1_API set23-34Name Event_05_code&lt;br /&gt;
attr PV_Anlage_1_API set23-35Name Event_05_description&lt;br /&gt;
attr PV_Anlage_1_API set23-36Name Event_05_end_time&lt;br /&gt;
attr PV_Anlage_1_API set23-37Name Event_05_group&lt;br /&gt;
attr PV_Anlage_1_API set23-38Name Event_05_is_active&lt;br /&gt;
attr PV_Anlage_1_API set23-39Name Event_05_long_description&lt;br /&gt;
attr PV_Anlage_1_API set23-3Name Event_01_description&lt;br /&gt;
attr PV_Anlage_1_API set23-40Name Event_05_start_time&lt;br /&gt;
attr PV_Anlage_1_API set23-4Name Event_01_end_time&lt;br /&gt;
attr PV_Anlage_1_API set23-5Name Event_01_group&lt;br /&gt;
attr PV_Anlage_1_API set23-6Name Event_01_is_active&lt;br /&gt;
attr PV_Anlage_1_API set23-7Name Event_01_long_description&lt;br /&gt;
attr PV_Anlage_1_API set23-8Name Event_01_start_time&lt;br /&gt;
attr PV_Anlage_1_API set23-9Name Event_02_category&lt;br /&gt;
attr PV_Anlage_1_API set23Data {&amp;quot;max&amp;quot;:5,&amp;quot;language&amp;quot;:&amp;quot;$val&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API set23Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set23Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set23Hint en-gb,de-de&lt;br /&gt;
attr PV_Anlage_1_API set23JSON .&lt;br /&gt;
attr PV_Anlage_1_API set23Name 23_/events/latest_5&lt;br /&gt;
attr PV_Anlage_1_API set23ParseResponse 1&lt;br /&gt;
attr PV_Anlage_1_API set23TextArg 1&lt;br /&gt;
attr PV_Anlage_1_API set23URL http://%IP-Address_Plenticore%/api/v1/events/latest&lt;br /&gt;
attr PV_Anlage_1_API set31Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:Type&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr PV_Anlage_1_API set31Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set31Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set31Hint 0,4&lt;br /&gt;
attr PV_Anlage_1_API set31Method PUT&lt;br /&gt;
attr PV_Anlage_1_API set31Name 31_Battery_Type&lt;br /&gt;
attr PV_Anlage_1_API set31URL http://%IP-Address_Plenticore%/api/v1/settings&lt;br /&gt;
attr PV_Anlage_1_API set33Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:Strategy&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr PV_Anlage_1_API set33Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set33Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set33Hint 1,2&lt;br /&gt;
attr PV_Anlage_1_API set33Method PUT&lt;br /&gt;
attr PV_Anlage_1_API set33Name 31_Battery_Strategy&lt;br /&gt;
attr PV_Anlage_1_API set33URL http://%IP-Address_Plenticore%/api/v1/settings&lt;br /&gt;
attr PV_Anlage_1_API set34Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:MinSoc&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr PV_Anlage_1_API set34Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set34Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set34Hint slider,10,5,100&lt;br /&gt;
attr PV_Anlage_1_API set34Method PUT&lt;br /&gt;
attr PV_Anlage_1_API set34Name 34_Battery_MinSoc&lt;br /&gt;
attr PV_Anlage_1_API set34URL http://%IP-Address_Plenticore%/api/v1/settings&lt;br /&gt;
attr PV_Anlage_1_API set35Data [{&amp;quot;moduleid&amp;quot;:&amp;quot;devices:local&amp;quot;,&amp;quot;settings&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;Battery:SmartBatteryControl:Enable&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;$val&amp;quot;}]}]&lt;br /&gt;
attr PV_Anlage_1_API set35Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set35Header02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API set35Hint 0,1&lt;br /&gt;
attr PV_Anlage_1_API set35Method PUT&lt;br /&gt;
attr PV_Anlage_1_API set35Name 35_SmartBatteryControl_Enable&lt;br /&gt;
attr PV_Anlage_1_API set35URL http://%IP-Address_Plenticore%/api/v1/settings&lt;br /&gt;
attr PV_Anlage_1_API set51Header01 authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API set51Header02 Accept: application/json, Connection: keep-alive, Content-type: application/json&lt;br /&gt;
attr PV_Anlage_1_API set51Method Post&lt;br /&gt;
attr PV_Anlage_1_API set51Name 51_/system/reboot&lt;br /&gt;
attr PV_Anlage_1_API set51NoArg 1&lt;br /&gt;
attr PV_Anlage_1_API set51URL http://%IP-Address_Plenticore%/api/v1/system/reboot&lt;br /&gt;
attr PV_Anlage_1_API showBody 1&lt;br /&gt;
attr PV_Anlage_1_API showError 1&lt;br /&gt;
attr PV_Anlage_1_API sid01Data {&amp;quot;nonce&amp;quot;: &amp;quot;%randomString64%&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API sid01ParseResponse 1&lt;br /&gt;
attr PV_Anlage_1_API sid01URL http://%IP-Address_Plenticore%/api/v1/auth/start&lt;br /&gt;
attr PV_Anlage_1_API sidHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr PV_Anlage_1_API sidHeader02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr PV_Anlage_1_API sortby 02&lt;br /&gt;
attr PV_Anlage_1_API timeout 7&lt;br /&gt;
attr PV_Anlage_1_API userReadings auth_first_called:auth_randomString64.* {my $first_called = InternalVal(&amp;quot;$NAME&amp;quot;,&amp;quot;path&amp;quot;,&amp;quot;n.a&amp;quot;);;;; $first_called =~ s/:/_/g;;;;$first_called ;;;;$first_called =~ s/\/api\/v1//g;;;; my %replace = (&amp;quot;/auth/me&amp;quot; =&amp;gt; &amp;quot;04_/auth/me&amp;quot;,&amp;quot;/info/version&amp;quot; =&amp;gt; &amp;quot;05_/info/version&amp;quot;,&amp;quot;/processdata/scb_statistic_EnergyFlow&amp;quot; =&amp;gt; &amp;quot;20_/processdata/scb_statistic_EnergyFlow&amp;quot;,&amp;quot;/modules_list&amp;quot; =&amp;gt; &amp;quot;21_/modules_list&amp;quot;,&amp;quot;/logdata/download&amp;quot; =&amp;gt; &amp;quot;24_/logdata/download&amp;quot;,&amp;quot;/update/status&amp;quot; =&amp;gt; &amp;quot;41_/update/status&amp;quot;,&amp;quot;/system/reboot&amp;quot; =&amp;gt; &amp;quot;04_/auth/me&amp;quot;,);;;; $replace{$first_called};;;;},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step1_Message:auth_transactionId.* {system(&amp;quot;/usr/bin/python3 /opt/fhem/python/bin/plenticore_auth_finish.py &amp;quot;.ReadingsVal(&amp;quot;PV_Anlage_1_config&amp;quot;,&amp;quot;IP-Address_FHEM&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;29000&amp;quot;).&amp;quot; &amp;amp;&amp;quot;);;;; &amp;quot;Prepare auth_finish started with auth_nonce &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;)},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step2_Message:auth_proof.* { fhem(&amp;quot;get &amp;quot;.$NAME.&amp;quot; 02_/auth/finish&amp;quot;) ;;;; &amp;quot;HTTP Request 02_/auth/finish with auth_proof &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_proof&amp;quot;,&amp;quot;&amp;quot;)},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step3_Message:auth_token.* {system(&amp;quot;/usr/bin/python3 /opt/fhem/python/bin/plenticore_auth_session.py &amp;quot;.ReadingsVal(&amp;quot;PV_Anlage_1_config&amp;quot;,&amp;quot;IP-Address_FHEM&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;amp;&amp;quot;);;;; &amp;quot;Prepare auth_session started with auth_token &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;&amp;quot;)},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step4_Message:auth_payload.* { fhem(&amp;quot;get &amp;quot;.$NAME.&amp;quot; 03_/auth/create_session&amp;quot;) ;;;; &amp;quot;HTTP Request 03_/auth/create_session with auth_authtag &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_authtag&amp;quot;,&amp;quot;&amp;quot;)},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step5_Message:auth_sessionId.* {my $restack = ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_first_called&amp;quot;,&amp;quot;&amp;quot;) ;;;; ($restack != &amp;quot;&amp;quot;)?fhem(&amp;quot;get &amp;quot;.$NAME.&amp;quot; &amp;quot;.$restack):&amp;quot;No further HTTP request&amp;quot;;;;;}&lt;br /&gt;
attr PV_Anlage_1_API verbose 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kostal Smart Energy Manager (KSEM) (Modbus/TCP) ===&lt;br /&gt;
Diese Einbindung ist nicht zwingend notwendig, jedoch weil es möglich ist hier beschrieben.&lt;br /&gt;
Das Gerät ist hier mit &amp;quot;disable 1&amp;quot; konfiguriert, um es zu verwenden muss das Attribut auf 0 gesetzt oder einfach gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist noch komplett deaktiviert, weshalb man seine Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_KSEM ModbusAttr 1 60 &amp;lt;IP-Address_KSEM&amp;gt;:502 TCP&lt;br /&gt;
attr PV_KSEM DbLogExclude .*&lt;br /&gt;
attr PV_KSEM alias PV_Energy_Manager&lt;br /&gt;
attr PV_KSEM dev-h-defPoll 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Current-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Current_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Current-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Current-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Current-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Freq-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Freq_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Freq-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Freq-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Freq-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_PF-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_PF_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_PF-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_PF-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_PF-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Power-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Power_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Power-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Power-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Power-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VA-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VA_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VA-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VA-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VA-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VAR-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VAR_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VAR-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VAR-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VAR-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Voltage-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Voltage_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Voltage-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Voltage-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Voltage-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-STR32-expr $val =~ s/[\00]+//gr&lt;br /&gt;
attr PV_KSEM dev-type-STR32-format %s&lt;br /&gt;
attr PV_KSEM dev-type-STR32-len 16&lt;br /&gt;
attr PV_KSEM dev-type-STR32-unpack a*&lt;br /&gt;
attr PV_KSEM dev-type-UINT16-format %s&lt;br /&gt;
attr PV_KSEM dev-type-UINT16-len 1&lt;br /&gt;
attr PV_KSEM dev-type-UINT32-format %s&lt;br /&gt;
attr PV_KSEM dev-type-UINT32-len 2&lt;br /&gt;
attr PV_KSEM dev-type-UINT64-expr $val/10000&lt;br /&gt;
attr PV_KSEM dev-type-UINT64-format %s&lt;br /&gt;
attr PV_KSEM dev-type-UINT64-len 4&lt;br /&gt;
attr PV_KSEM dev-type-UINT64-unpack Q&amp;gt;&lt;br /&gt;
attr PV_KSEM disable 1&lt;br /&gt;
attr PV_KSEM group PV Eigenverbrauch&lt;br /&gt;
attr PV_KSEM icon measure_power&lt;br /&gt;
attr PV_KSEM obj-h40072-reading M_AC_Current_A&lt;br /&gt;
attr PV_KSEM obj-h40072-type INT16_Current&lt;br /&gt;
attr PV_KSEM obj-h40073-reading M_AC_Current_B&lt;br /&gt;
attr PV_KSEM obj-h40073-type INT16_Current&lt;br /&gt;
attr PV_KSEM obj-h40074-reading M_AC_Current_C&lt;br /&gt;
attr PV_KSEM obj-h40074-type INT16_Current&lt;br /&gt;
attr PV_KSEM obj-h40075-reading M_AC_Current_SF&lt;br /&gt;
attr PV_KSEM obj-h40075-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40077-reading M_AC_Voltage_AN&lt;br /&gt;
attr PV_KSEM obj-h40077-type INT16_Voltage&lt;br /&gt;
attr PV_KSEM obj-h40078-reading M_AC_Voltage_BN&lt;br /&gt;
attr PV_KSEM obj-h40078-type INT16_Voltage&lt;br /&gt;
attr PV_KSEM obj-h40079-reading M_AC_Voltage_CN&lt;br /&gt;
attr PV_KSEM obj-h40079-type INT16_Voltage&lt;br /&gt;
attr PV_KSEM obj-h40084-reading M_AC_Voltage_SF&lt;br /&gt;
attr PV_KSEM obj-h40084-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40085-reading M_AC_Freq&lt;br /&gt;
attr PV_KSEM obj-h40085-type INT16_Freq&lt;br /&gt;
attr PV_KSEM obj-h40086-reading M_AC_Freq_SF&lt;br /&gt;
attr PV_KSEM obj-h40086-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40087-reading M_AC_Power&lt;br /&gt;
attr PV_KSEM obj-h40087-type INT16_Power&lt;br /&gt;
attr PV_KSEM obj-h40088-reading M_AC_Power_A&lt;br /&gt;
attr PV_KSEM obj-h40088-type INT16_Power&lt;br /&gt;
attr PV_KSEM obj-h40089-reading M_AC_Power_B&lt;br /&gt;
attr PV_KSEM obj-h40089-type INT16_Power&lt;br /&gt;
attr PV_KSEM obj-h40090-reading M_AC_Power_C&lt;br /&gt;
attr PV_KSEM obj-h40090-type INT16_Power&lt;br /&gt;
attr PV_KSEM obj-h40091-reading M_AC_Power_SF&lt;br /&gt;
attr PV_KSEM obj-h40091-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40092-reading M_AC_VA&lt;br /&gt;
attr PV_KSEM obj-h40092-type INT16_VA&lt;br /&gt;
attr PV_KSEM obj-h40093-reading M_AC_VA_A&lt;br /&gt;
attr PV_KSEM obj-h40093-type INT16_VA&lt;br /&gt;
attr PV_KSEM obj-h40094-reading M_AC_VA_B&lt;br /&gt;
attr PV_KSEM obj-h40094-type INT16_VA&lt;br /&gt;
attr PV_KSEM obj-h40095-reading M_AC_VA_C&lt;br /&gt;
attr PV_KSEM obj-h40095-type INT16_VA&lt;br /&gt;
attr PV_KSEM obj-h40096-reading M_AC_VA_SF&lt;br /&gt;
attr PV_KSEM obj-h40096-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40097-reading M_AC_VAR&lt;br /&gt;
attr PV_KSEM obj-h40097-type INT16_VAR&lt;br /&gt;
attr PV_KSEM obj-h40098-reading M_AC_VAR_A&lt;br /&gt;
attr PV_KSEM obj-h40098-type INT16_VAR&lt;br /&gt;
attr PV_KSEM obj-h40099-reading M_AC_VAR_B&lt;br /&gt;
attr PV_KSEM obj-h40099-type INT16_VAR&lt;br /&gt;
attr PV_KSEM obj-h40100-reading M_AC_VAR_C&lt;br /&gt;
attr PV_KSEM obj-h40100-type INT16_VAR&lt;br /&gt;
attr PV_KSEM obj-h40101-reading M_AC_VAR_SF&lt;br /&gt;
attr PV_KSEM obj-h40101-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40102-reading M_AC_PF&lt;br /&gt;
attr PV_KSEM obj-h40102-type INT16_PF&lt;br /&gt;
attr PV_KSEM obj-h40103-reading M_AC_PF_A&lt;br /&gt;
attr PV_KSEM obj-h40103-type INT16_PF&lt;br /&gt;
attr PV_KSEM obj-h40104-reading M_AC_PF_B&lt;br /&gt;
attr PV_KSEM obj-h40104-type INT16_PF&lt;br /&gt;
attr PV_KSEM obj-h40105-reading M_AC_PF_C&lt;br /&gt;
attr PV_KSEM obj-h40105-type INT16_PF&lt;br /&gt;
attr PV_KSEM obj-h40106-reading M_AC_PF_SF&lt;br /&gt;
attr PV_KSEM obj-h40106-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40108-reading M_Exported&lt;br /&gt;
attr PV_KSEM obj-h40108-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40110-reading M_Exported_A&lt;br /&gt;
attr PV_KSEM obj-h40110-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40112-reading M_Exported_B&lt;br /&gt;
attr PV_KSEM obj-h40112-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40114-reading M_Exported_C&lt;br /&gt;
attr PV_KSEM obj-h40114-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40116-reading M_Imported&lt;br /&gt;
attr PV_KSEM obj-h40116-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40118-reading M_Imported_A&lt;br /&gt;
attr PV_KSEM obj-h40118-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40120-reading M_Imported_B&lt;br /&gt;
attr PV_KSEM obj-h40120-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40122-reading M_Imported_C&lt;br /&gt;
attr PV_KSEM obj-h40122-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40125-reading M_Exported_VA&lt;br /&gt;
attr PV_KSEM obj-h40125-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40127-reading M_Exported_VA_A&lt;br /&gt;
attr PV_KSEM obj-h40127-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40129-reading M_Exported_VA_B&lt;br /&gt;
attr PV_KSEM obj-h40129-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40131-reading M_Exported_VA_C&lt;br /&gt;
attr PV_KSEM obj-h40131-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40133-reading M_Imported_VA&lt;br /&gt;
attr PV_KSEM obj-h40133-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40135-reading M_Imported_VA_A&lt;br /&gt;
attr PV_KSEM obj-h40135-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40137-reading M_Imported_VA_B&lt;br /&gt;
attr PV_KSEM obj-h40137-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40139-reading M_Imported_VA_C&lt;br /&gt;
attr PV_KSEM obj-h40139-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h512-reading Active_energy+&lt;br /&gt;
attr PV_KSEM obj-h512-type UINT64&lt;br /&gt;
attr PV_KSEM obj-h516-reading Active_energy-&lt;br /&gt;
attr PV_KSEM obj-h516-type UINT64&lt;br /&gt;
attr PV_KSEM obj-h8192-reading ManufacturerID&lt;br /&gt;
attr PV_KSEM obj-h8192-type UINT16&lt;br /&gt;
attr PV_KSEM obj-h8193-reading ProductID&lt;br /&gt;
attr PV_KSEM obj-h8193-type UINT16&lt;br /&gt;
attr PV_KSEM obj-h8194-reading ProductVersion&lt;br /&gt;
attr PV_KSEM obj-h8194-type UINT16&lt;br /&gt;
attr PV_KSEM obj-h8195-reading FirmwareVersion&lt;br /&gt;
attr PV_KSEM obj-h8195-type UINT16&lt;br /&gt;
attr PV_KSEM obj-h8196-reading VendorName&lt;br /&gt;
attr PV_KSEM obj-h8196-type STR32&lt;br /&gt;
attr PV_KSEM obj-h8212-reading Productname&lt;br /&gt;
attr PV_KSEM obj-h8212-type STR32&lt;br /&gt;
attr PV_KSEM obj-h8228-reading SerialNumber&lt;br /&gt;
attr PV_KSEM obj-h8228-type STR32&lt;br /&gt;
attr PV_KSEM obj-h8244-reading MeasuringInterval&lt;br /&gt;
attr PV_KSEM obj-h8244-type UINT16&lt;br /&gt;
attr PV_KSEM room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_KSEM sortby 03&lt;br /&gt;
attr PV_KSEM userReadings M_AC_Current:M_AC_Current_.* { ReadingsVal($NAME,&amp;quot;M_AC_Current_A&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_B&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_C&amp;quot;,0) }&lt;br /&gt;
attr PV_KSEM verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== BYD Speicher (über Python Skript) ===&lt;br /&gt;
Diese Einbindung ist nicht zwingend notwendig.&lt;br /&gt;
Ein Ziel ist es das Python Skript später zu entfernen und eine direkten HTTPMOD Abfrage zu implementieren.&lt;br /&gt;
==== byd_status.py ====&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ cat byd_status.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Copyright: Kilian Knoll, 10.3.2019&lt;br /&gt;
#&lt;br /&gt;
# Utility to parse rundata values of BYD HV BOX&lt;br /&gt;
# Version 1.0&lt;br /&gt;
#  &lt;br /&gt;
#  This program is free software: you can redistribute it and/or modify&lt;br /&gt;
#  it under the terms of the GNU General Public License as published by&lt;br /&gt;
#  the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
#  (at your option) any later version.&lt;br /&gt;
#&lt;br /&gt;
#  This program is distributed in the hope that it will be useful,&lt;br /&gt;
#  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
#  GNU General Public License for more details.&lt;br /&gt;
#&lt;br /&gt;
#  You should have received a copy of the GNU General Public License&lt;br /&gt;
#  along with this program.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#  Please note that any incorrect or careless usage of this module as well as errors in the implementation can damage your BYD box!&lt;br /&gt;
#  Therefore, the author does not provide any guarantee or warranty concerning to correctness, functionality or performance and does not accept any liability for damage caused by this module, examples or mentioned information.&lt;br /&gt;
#  Thus, use it at your own risk!&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#  Purpose: &lt;br /&gt;
#     Query Rundata values from BYD box via local network connection &lt;br /&gt;
#     Used with BYD HV 6.4&lt;br /&gt;
#&lt;br /&gt;
#     Returnvalue: 0    (Everything all right)&lt;br /&gt;
#     Returnvalue: -1   (Crap happened)&lt;br /&gt;
#     BYDdata:          (Empty list in case Returnvalue =-1)&lt;br /&gt;
#     BYDdata:          (Full list of key-value pairs in case Returnvalue = 0)&lt;br /&gt;
#&lt;br /&gt;
# Tested with&lt;br /&gt;
#   BYD HV 6.4,&lt;br /&gt;
#   Firmware verison V3.012 R&lt;br /&gt;
#   python 3.6&lt;br /&gt;
#&lt;br /&gt;
# Changes:&lt;br /&gt;
# 2020.07.30 added fhem connectivity &lt;br /&gt;
#            added sys for argument parsing; BYDboxIP and FHEM Web Interface are read from commandline&lt;br /&gt;
#            password and username is read from file&lt;br /&gt;
&lt;br /&gt;
import fhem&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
BYDboxIP = sys.argv[1]&lt;br /&gt;
web      = sys.argv[2]&lt;br /&gt;
&lt;br /&gt;
import requests&lt;br /&gt;
import time &lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
from pprint import pprint&lt;br /&gt;
from bs4 import BeautifulSoup &lt;br /&gt;
from requests.auth import HTTPBasicAuth &lt;br /&gt;
import logging&lt;br /&gt;
&lt;br /&gt;
#from loggerdate import loggerdate&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def getvaluefromsubstring (inputvalue):&lt;br /&gt;
    # The input we pass looks like this:&lt;br /&gt;
    #&amp;lt;input readonly=&amp;quot;readonly&amp;quot; type=&amp;quot;text&amp;quot; value=&amp;quot;5186&amp;quot;/&amp;gt;&lt;br /&gt;
    #Goal is to return value 5186 as outputvalue&lt;br /&gt;
    #Not sure if BeautifulSoup could do more / better... &lt;br /&gt;
    output_array=  str(inputvalue)&lt;br /&gt;
    A,B,C,outputvalue=  output_array.split(&#039;=&#039;)&lt;br /&gt;
    outputvalue, A= outputvalue.split(&#039;/&#039;)&lt;br /&gt;
    A,outputvalue,B = outputvalue.split(&#039;&amp;quot;&#039;)&lt;br /&gt;
    if (&#039;%&#039; in outputvalue):&lt;br /&gt;
        outputvalue, A = outputvalue.split(&#039;%&#039;)&lt;br /&gt;
    outputvalue = float(outputvalue)&lt;br /&gt;
    return outputvalue&lt;br /&gt;
&lt;br /&gt;
def readbyd():&lt;br /&gt;
&lt;br /&gt;
    #Please adjust the parameters below as appropriate for your environment:&lt;br /&gt;
&lt;br /&gt;
    # username and password are read from pwd_byd.json file ; BYDboxIP is parsed from sys commandline&lt;br /&gt;
    #print (&amp;quot;Start reading Password file for BYD access....&amp;quot;)&lt;br /&gt;
    try:&lt;br /&gt;
        with open(&#039;/opt/fhem/python/pwd_byd.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
            credentials=json.load(f)&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
    #No configurable parameters beyond this point        &lt;br /&gt;
    &lt;br /&gt;
    mySession = requests.Session()&lt;br /&gt;
    try:&lt;br /&gt;
        BYDdata={}&lt;br /&gt;
        #The two stupid lines below took me almost a day...&lt;br /&gt;
        #You can access other pages on the BYD WEB-Page - calling other asp scripts&lt;br /&gt;
        url=&#039;http://&#039;+BYDboxIP+&#039;/asp/RunData.asp&#039;&lt;br /&gt;
        r4 = mySession.get(url, auth=HTTPBasicAuth(credentials[&amp;quot;username&amp;quot;],credentials[&amp;quot;password&amp;quot;]))&lt;br /&gt;
        if (r4.status_code == 200):&lt;br /&gt;
            page = r4.text &lt;br /&gt;
            soup = BeautifulSoup(page, &#039;html.parser&#039;)&lt;br /&gt;
            soup_ele = soup.body.form.table                                    #This gets us the RunData Table and Array Num 1 values - using this approach&lt;br /&gt;
            soup_reduced = soup_ele.find_all(&#039;input&#039;,attrs={&amp;quot;type&amp;quot;: &amp;quot;text&amp;quot;} )  #Using this option now since BYD introduced some glitches with Firmware 3.012R on their html code.. &lt;br /&gt;
            # It now contains a list of the following kind&lt;br /&gt;
            #&amp;lt;input readonly=&amp;quot;readonly&amp;quot; type=&amp;quot;text&amp;quot; value=&amp;quot;19.300&amp;quot;/&amp;gt;&lt;br /&gt;
            #print (soup_reduced)&lt;br /&gt;
            #print (&amp;quot;ERSTES ELE&amp;quot;, soup_reduced[1]) &lt;br /&gt;
            Keyvalue=[]&lt;br /&gt;
            for elems in soup_reduced:&lt;br /&gt;
                elems=str(elems)&lt;br /&gt;
                myarray= elems.split(&#039;=&#039;)&lt;br /&gt;
                CurValue=myarray[3].split(&#039;&amp;quot;&#039;)&lt;br /&gt;
                Keyvalue.append(CurValue[1])&lt;br /&gt;
&lt;br /&gt;
            BYDdata[&amp;quot;arrayvoltage&amp;quot;]= float(Keyvalue[0])&lt;br /&gt;
            BYDdata[&amp;quot;packvoltage&amp;quot;] = float(Keyvalue[1])&lt;br /&gt;
            BYDdata[&amp;quot;current&amp;quot;] = float(Keyvalue[2])&lt;br /&gt;
            BYDdata[&amp;quot;soc&amp;quot;] = (Keyvalue[3])&lt;br /&gt;
            BYDdata[&amp;quot;sysTemp&amp;quot;] = Keyvalue[4]         &lt;br /&gt;
            BYDdata[&amp;quot;maxcellvol&amp;quot;] = float(Keyvalue[5])&lt;br /&gt;
            BYDdata[&amp;quot;mincellvol&amp;quot;] = float(Keyvalue[6])       &lt;br /&gt;
            BYDdata[&amp;quot;maxcelltemp&amp;quot;] = float(Keyvalue[7])&lt;br /&gt;
            BYDdata[&amp;quot;mincelltemp&amp;quot;] = float(Keyvalue[8])&lt;br /&gt;
            BYDdata[&amp;quot;maxvolpos&amp;quot;] = int(Keyvalue[9])&lt;br /&gt;
            BYDdata[&amp;quot;minvolpos&amp;quot;] = Keyvalue[10]&lt;br /&gt;
            BYDdata[&amp;quot;maxtemppos&amp;quot;] = Keyvalue[11]&lt;br /&gt;
            BYDdata[&amp;quot;mintemppos&amp;quot;] = Keyvalue[12]&lt;br /&gt;
            BYDdata[&amp;quot;power&amp;quot;] = Keyvalue[13]            &lt;br /&gt;
            &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
            # Oh well - with Firmware 3.012R, these values have disappeared from the BYD web pages...&lt;br /&gt;
            BYDdata[&amp;quot;soc&amp;quot;] = Keyvalue[3]&lt;br /&gt;
            BYDdata[&amp;quot;socwh&amp;quot;] = Keyvalue[4]&lt;br /&gt;
            BYDdata[&amp;quot;socah&amp;quot;] = Keyvalue[5]   &lt;br /&gt;
            BYDdata[&amp;quot;soh&amp;quot;] = Keyvalue[6]                 &lt;br /&gt;
            &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
            Error_Connecting = 0&lt;br /&gt;
&lt;br /&gt;
        else:&lt;br /&gt;
            print (&amp;quot;Not sure if we are able to connect with the given username &amp;amp; password - error code is:&amp;quot;, r4.status_code)&lt;br /&gt;
            print (&amp;quot;Header information passed is :&amp;quot;, r4.headers)&lt;br /&gt;
            Error_Connecting = r4.status_code&lt;br /&gt;
    &lt;br /&gt;
        url=&#039;http://&#039;+BYDboxIP+&#039;/asp/StatisticInformation.asp&#039;&lt;br /&gt;
        r2 = mySession.get(url, auth=HTTPBasicAuth(credentials[&amp;quot;username&amp;quot;],credentials[&amp;quot;password&amp;quot;]))&lt;br /&gt;
        if ((r2.status_code == 200) and (Error_Connecting == 0)):&lt;br /&gt;
            page = r2.text &lt;br /&gt;
            soup = BeautifulSoup(page, &#039;html.parser&#039;)&lt;br /&gt;
            soup_ele = soup.body.table   &lt;br /&gt;
            #print (soup_ele)&lt;br /&gt;
            #print (&amp;quot;--------------------------------------------------------&amp;quot;)&lt;br /&gt;
            #&amp;lt;input readonly=&amp;quot;readonly&amp;quot; type=&amp;quot;text&amp;quot; value=&amp;quot;5186&amp;quot;/&amp;gt;&lt;br /&gt;
            soup_reduced = soup_ele.find_all(&#039;input&#039;)&lt;br /&gt;
            #print (soup_reduced)&lt;br /&gt;
            #print (&amp;quot;soup_ele&amp;quot;, soup_ele)&lt;br /&gt;
            i = 0&lt;br /&gt;
            a= len(soup_ele.contents)&lt;br /&gt;
            total_charge_energy = soup_ele.find(&amp;quot;td&amp;quot;, text=&amp;quot;Total Charge Energy:&amp;quot;).find_next_sibling(&amp;quot;td&amp;quot;).text&lt;br /&gt;
            total_charge_energy,b = (total_charge_energy.split())&lt;br /&gt;
            total_charge_energy = float(total_charge_energy)&lt;br /&gt;
            #print (&amp;quot;Total Charge Energy :&amp;quot;, total_charge_energy)&lt;br /&gt;
            BYDdata[&amp;quot;Total_Charge_Energy&amp;quot;]= total_charge_energy&lt;br /&gt;
            &lt;br /&gt;
            total_discharge_energy = soup_ele.find(&amp;quot;td&amp;quot;, text=&amp;quot;Total Discharge Energy:&amp;quot;).find_next_sibling(&amp;quot;td&amp;quot;).text&lt;br /&gt;
            total_discharge_energy,b = (total_discharge_energy.split())&lt;br /&gt;
            total_discharge_energy = float(total_discharge_energy)&lt;br /&gt;
            #print (&amp;quot;Total Discharge Energy :&amp;quot;, total_discharge_energy)&lt;br /&gt;
            BYDdata[&amp;quot;Total_Discharge_Energy&amp;quot;] = total_discharge_energy&lt;br /&gt;
            &lt;br /&gt;
            total_cycle_counts = soup_ele.find(&amp;quot;td&amp;quot;, text=&amp;quot;Total Cycle Counts:&amp;quot;).find_next_sibling(&amp;quot;td&amp;quot;).text&lt;br /&gt;
            #total_cycle_counts,b = (total_cycle_counts.split())&lt;br /&gt;
            total_cycle_counts = float(total_cycle_counts)&lt;br /&gt;
            #print (&amp;quot;Total Cycle Counts :&amp;quot;, total_cycle_counts) &lt;br /&gt;
            BYDdata[&amp;quot;Total_Cycle_Counts&amp;quot;] = total_cycle_counts&lt;br /&gt;
        else:&lt;br /&gt;
            print (&amp;quot;Not sure if we are able to connect with the given username &amp;amp; password - error code is:&amp;quot;, r4.status_code)&lt;br /&gt;
            print (&amp;quot;Header information passed is :&amp;quot;, r2.headers)&lt;br /&gt;
            Error_Connecting = r2.status_code&lt;br /&gt;
            &lt;br /&gt;
    except Exception as Connecterror:&lt;br /&gt;
        print (&amp;quot;Error connecting to the BYD box :&amp;quot;, Connecterror)&lt;br /&gt;
        #logging.error(&amp;quot;%s %s %s&amp;quot;, loggerdate(), &amp;quot;,readbyd: Ran into exception querying the BYD Box : &amp;quot;, Connecterror)&lt;br /&gt;
        Error_Connecting = Connecterror&lt;br /&gt;
    if (Error_Connecting == 0):&lt;br /&gt;
        if (len(BYDdata) &amp;gt;1):                         # We have something in the list&lt;br /&gt;
&lt;br /&gt;
            Returnvalue =0&lt;br /&gt;
    else:                                               # We ran into trouble and allocate an empty list&lt;br /&gt;
        BYDdata={}&lt;br /&gt;
        print (&amp;quot;Issue getting data from BYD &amp;quot;, Error_Connecting)&lt;br /&gt;
        &lt;br /&gt;
    return (Returnvalue, BYDdata)    &lt;br /&gt;
        &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:  &lt;br /&gt;
&lt;br /&gt;
    #print (&amp;quot;Start querying BYD....&amp;quot;)&lt;br /&gt;
    try:&lt;br /&gt;
        Myreturnvalue, Mydata = readbyd();&lt;br /&gt;
        if (Myreturnvalue == 0):&lt;br /&gt;
            #print (&amp;quot;Returnvalue -should be zero if successful : &amp;quot;, Myreturnvalue)&lt;br /&gt;
            #print (&amp;quot;----------------Start Values BYD ----------------&amp;quot;)&lt;br /&gt;
            #pprint (Mydata)&lt;br /&gt;
            #print (&amp;quot;----------------End - Values from BYD ----------------&amp;quot;)	&lt;br /&gt;
            #print (&amp;quot;Specific values from array....&amp;quot;)&lt;br /&gt;
            #print (&amp;quot;BYD Total Charge Energy                 :&amp;quot;, Mydata[&#039;Total_Charge_Energy&#039;], &amp;quot;Kwh&amp;quot;)&lt;br /&gt;
            #print (&amp;quot;BYD Total Discharge Energy              :&amp;quot;, Mydata[&#039;Total_Discharge_Energy&#039;], &amp;quot;Kwh&amp;quot;)&lt;br /&gt;
            #print (&amp;quot;Calculations...&amp;quot;)&lt;br /&gt;
            #print (&amp;quot;Charging (+) / Discharging (-) Energy   :&amp;quot;, round(Mydata[&#039;packvoltage&#039;]*Mydata[&#039;current&#039;],0), &amp;quot;W&amp;quot;)&lt;br /&gt;
            #print (&amp;quot;Efficiency is                           :&amp;quot;,round(Mydata[&#039;Total_Discharge_Energy&#039;]/Mydata[&#039;Total_Charge_Energy&#039;],3))&lt;br /&gt;
            #print (Mydata)&lt;br /&gt;
&lt;br /&gt;
            message = json.dumps(Mydata)&lt;br /&gt;
&lt;br /&gt;
            #print (&amp;quot;Start reading Password file for FHEM access....&amp;quot;)&lt;br /&gt;
            try:&lt;br /&gt;
                with open(&#039;/opt/fhem/python/pwd_fhem.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
                    credentials=json.load(f)&lt;br /&gt;
            except Exception as e:&lt;br /&gt;
                print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
            #print (&amp;quot;Start login to FHEM ....&amp;quot;)&lt;br /&gt;
            fh = fhem.Fhem(web, protocol=&amp;quot;http&amp;quot;, port=8083, username=credentials[&amp;quot;username&amp;quot;], password=credentials[&amp;quot;password&amp;quot;])&lt;br /&gt;
&lt;br /&gt;
            #print (&amp;quot;Start transfer of data to FHEM ....&amp;quot;)&lt;br /&gt;
            fh.send_cmd(&amp;quot;setreading BYD_Status output &amp;quot; + message)&lt;br /&gt;
&lt;br /&gt;
        else:&lt;br /&gt;
            print (&amp;quot;Error unable to query BYD Box&amp;quot;)&lt;br /&gt;
    except Exception as ex:&lt;br /&gt;
        print (&amp;quot;Issues querying BYD Box :&amp;quot;, ex)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
====== Userreadings ======&lt;br /&gt;
Die Userreadings gehören zum Gerät BYD_Status .&lt;br /&gt;
&lt;br /&gt;
output&lt;br /&gt;
   Trigger: externes Python Skript&lt;br /&gt;
   Das Python Skript beschreibt im Gerät BYD_Status das reading output, das dort dann weiter verarbeitet wird.&lt;br /&gt;
&lt;br /&gt;
====== Passworte ======&lt;br /&gt;
Das Passwort für den BYD Speicher liegt in einer JSON Datei&lt;br /&gt;
&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_byd.json&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;username&amp;quot;: &amp;quot;installer&amp;quot;,&lt;br /&gt;
    &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Steht in der BYD Dokumentation&amp;gt;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== RAW Definition BYD_Status ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod BYD_Status expandJSON BYD_Status:output:.\{.*}&lt;br /&gt;
attr BYD_Status DbLogExclude .*&lt;br /&gt;
attr BYD_Status alias BYD_Status&lt;br /&gt;
attr BYD_Status comment Das Device wird über ein Python Skript im reading output befüllt.\&lt;br /&gt;
deletereading BYD_Status [min|max|cur|array|Total|pack|power|soc|sys].*\&lt;br /&gt;
&lt;br /&gt;
attr BYD_Status group PV Eigenverbrauch&lt;br /&gt;
attr BYD_Status icon measure_battery_50&lt;br /&gt;
attr BYD_Status room Strom-&amp;gt;Photovoltaik,Strom-&amp;gt;System&lt;br /&gt;
attr BYD_Status sortby 02&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
== Timeing für die PV extra Funktionen ==&lt;br /&gt;
=== RAW Definition PV_Schedule (DOIF) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Schedule DOIF ################################################################################################################\&lt;br /&gt;
## 1 BYD Status aktualisieren\&lt;br /&gt;
##\&lt;br /&gt;
 ([+:05] and !([:00] or [:30]))\&lt;br /&gt;
   (\&lt;br /&gt;
      {system(&amp;quot;/usr/bin/python3 /opt/fhem/python/bin/byd_status.py &amp;quot;.ReadingsVal(&amp;quot;BYD_Status&amp;quot;,&amp;quot;IP-Address_BYD&amp;quot;,&amp;quot;?&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;BYD_Status&amp;quot;,&amp;quot;IP-Address_FHEM&amp;quot;,&amp;quot;?&amp;quot;).&amp;quot; &amp;amp;&amp;quot;)}\&lt;br /&gt;
   )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Plenticore Status aktualisieren. Dies geschieht über das PV_Anlage_1_API Device\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([:57])\&lt;br /&gt;
   (\&lt;br /&gt;
   get PV_Anlage_1_API 20_/processdata/scb_statistic_EnergyFlow\&lt;br /&gt;
   set Dum.Energy update\&lt;br /&gt;
\&lt;br /&gt;
   )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 DWD Prognose aktualisieren, die Daten stehen immer verzögert zur Verfügung.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([06:37] or [11:37] or [17:37] or [00:37])\&lt;br /&gt;
   (\&lt;br /&gt;
    {system(&amp;quot;/usr/bin/python3 /opt/fhem/python/bin/dwd_get_forecast.py &amp;quot;.ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;IP-Address_FHEM&amp;quot;,&amp;quot;?&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Solar_Station&amp;quot;,&amp;quot;?&amp;quot;).&amp;quot; &amp;amp;&amp;quot;)}\&lt;br /&gt;
   )\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 PV Prognose vom aktuellen Tag aktualisieren\&lt;br /&gt;
##     zwischen 7 und 19 Uhr zur vollen Stunde\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([07:00-19:00] and [:00])\&lt;br /&gt;
   (\&lt;br /&gt;
    {Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_delete_PV_Forecast&amp;quot;,&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Prognose&amp;quot;,&amp;quot;ProPlanta&amp;quot;,0)}\&lt;br /&gt;
   )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 PV Prognose für den nächsten Tag aktualisieren\&lt;br /&gt;
## \&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([09:11])\&lt;br /&gt;
   (\&lt;br /&gt;
    {Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_delete_PV_Forecast&amp;quot;,&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;DWD_Prognose&amp;quot;,&amp;quot;ProPlanta&amp;quot;,1)}\&lt;br /&gt;
   )\&lt;br /&gt;
&lt;br /&gt;
attr PV_Schedule DbLogExclude .*&lt;br /&gt;
attr PV_Schedule alias PV_Schedule&lt;br /&gt;
attr PV_Schedule cmdState BYD Status|Plenticore Status&lt;br /&gt;
attr PV_Schedule do always&lt;br /&gt;
attr PV_Schedule room Strom-&amp;gt;System&lt;br /&gt;
attr PV_Schedule sortby 11&lt;br /&gt;
attr PV_Schedule wait 0:0:0:10:0:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Energie Bilanz ==&lt;br /&gt;
[[Bild:Plenticore Bilanz.png|mini|900px|rechts|]]&lt;br /&gt;
Die Energie Bilanz soll einen kompakten Überblick über die Produktions und Verbrauchswerte Liefern. Hierbei werden die Momentanwerte direkt berechnet, die restlichen Werte werden als Statistiken aus dem Gerät abgefragt.&lt;br /&gt;
Die Aktualisierung erfolgt zyklisch über das Gerät PV_Schedule.&lt;br /&gt;
=== RAW Definition Energiebilanz ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Dum.Energy dummy&lt;br /&gt;
attr Dum.Energy DbLogExclude .*&lt;br /&gt;
attr Dum.Energy DbLogInclude Autarky.*,GridFeed.*,PV.*,.*Consumption.*&lt;br /&gt;
attr Dum.Energy alias Energiebilanz&lt;br /&gt;
attr Dum.Energy comment TotalConsumption,AutarkyQuoteDay,SelfConsumptionQuoteDay,AutarkyQuoteMonth,SelfConsumptionQuoteMonth&lt;br /&gt;
attr Dum.Energy event-on-change-reading PV,GridConsumption,GridFeedIn,SelfConsumptionQuote,Autarky.*,GridFeed.*,PV.*,.*Consumption.*&lt;br /&gt;
attr Dum.Energy event-on-update-reading TotalConsumption,AutarkyQuoteDay,SelfConsumptionQuoteDay,AutarkyQuoteMonth,SelfConsumptionQuoteMonth&lt;br /&gt;
attr Dum.Energy group Energiebilanz&lt;br /&gt;
attr Dum.Energy icon measure_power_meter&lt;br /&gt;
attr Dum.Energy room Strom-&amp;gt;Energie&lt;br /&gt;
attr Dum.Energy stateFormat {\&lt;br /&gt;
 my $pvt   = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVTotal&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $pvtd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVTotalDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $pvtm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVTotalMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $pvty  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVTotalYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $pv  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PV&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $pvd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $pvm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $pvy  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $gfi  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridFeedIn&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $gfid = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridFeedInDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $gfim = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridFeedInMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $gfiy = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridFeedInYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $eb   = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridConsumption&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $ebd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridConsumptionDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $ebm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridConsumptionMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $eby  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridConsumptionYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $et   = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;TotalConsumption&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $etd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;TotalConsumptionDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $etm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;TotalConsumptionMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $ety  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;TotalConsumptionYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $aq   = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;AutarkyQuote&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $aqd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;AutarkyQuoteDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $aqm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;AutarkyQuoteMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $aqy  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;AutarkyQuoteYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $sq   = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SelfConsumptionQuote&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $sqd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SelfConsumptionQuoteDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $sqm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SelfConsumptionQuoteMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $sqy  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SelfConsumptionQuoteYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $md   = ReadingsTimestamp(&amp;quot;$name&amp;quot;, &amp;quot;AutarkyQuote&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
 my $cd   = ReadingsTimestamp(&amp;quot;PV_Anlage_1_API&amp;quot;, &amp;quot;Statistic_Autarky_Day&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
 my $cm   = ReadingsTimestamp(&amp;quot;PV_Anlage_1_API&amp;quot;, &amp;quot;Statistic_Autarky_Month&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
 my $cy   = ReadingsTimestamp(&amp;quot;PV_Anlage_1_API&amp;quot;, &amp;quot;Statistic_Autarky_Year&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt; &amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;aktueller Wert&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;Heute&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;dieser Monat&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;dieses Jahr&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;PV-Erzeugung-Total&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvt.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvtd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvtm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvty.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;PV-Einspeisung&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$gfi.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$gfid.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$gfim.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$gfiy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Netz-Bezug&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$eb.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$ebd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$ebm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$eby.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;PV-Bezug&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pv.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Energieverbrauch&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$et.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$etd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$etm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$ety.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Autarkiequote&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$aq.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$aqd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$aqm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$aqy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Eigenverbrauchsquote&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$sq.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$sqd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$sqm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$sqy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Berechnung am&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$md.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$cd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$cm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$cy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;/table&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr Dum.Energy userReadings PVTotal {round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_AC_active_power&amp;quot;,&amp;quot;&amp;quot;),0)},\&lt;br /&gt;
PVTotalDay {round( ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;, &amp;quot;&amp;quot;)/1000 ,2)},\&lt;br /&gt;
PVTotalMonth {round( ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;, &amp;quot;&amp;quot;)/1000 ,2)},\&lt;br /&gt;
PVTotalYear {round( ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;, &amp;quot;&amp;quot;)/1000 ,2)},\&lt;br /&gt;
\&lt;br /&gt;
PV {round( ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_battery&amp;quot;, &amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_PV&amp;quot;, &amp;quot;&amp;quot;) ,0)},\&lt;br /&gt;
PVDay {round( (ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;, &amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;, &amp;quot;&amp;quot;))/1000 ,2)},\&lt;br /&gt;
PVMonth {round( (ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;, &amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;, &amp;quot;&amp;quot;))/1000 ,2)},\&lt;br /&gt;
PVYear {round( (ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;, &amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;, &amp;quot;&amp;quot;))/1000 ,2)},\&lt;br /&gt;
\&lt;br /&gt;
GridFeedIn { ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0)&amp;lt;=0 ? abs(round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0),0)) : 0  },\&lt;br /&gt;
GridFeedInDay {round((ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;, &amp;quot;&amp;quot;))/1000,2)},\&lt;br /&gt;
GridFeedInMonth {round((ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;, &amp;quot;&amp;quot;))/1000,2)},\&lt;br /&gt;
GridFeedInYear {round((ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;, &amp;quot;&amp;quot;))/1000,2)},\&lt;br /&gt;
\&lt;br /&gt;
GridConsumption { ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0)&amp;gt;=0 ? round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0),0) : 0  },\&lt;br /&gt;
GridConsumptionDay {round(abs(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Day&amp;quot;,&amp;quot;&amp;quot;))/1000 ,2)},\&lt;br /&gt;
GridConsumptionMonth {round(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Month&amp;quot;,&amp;quot;&amp;quot;)/1000 ,2)},\&lt;br /&gt;
GridConsumptionYear {round(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Year&amp;quot;,&amp;quot;&amp;quot;)/1000 ,2)},\&lt;br /&gt;
\&lt;br /&gt;
TotalConsumption {round((ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_PV&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_battery&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_grid&amp;quot;,&amp;quot;&amp;quot;)),0)},\&lt;br /&gt;
\&lt;br /&gt;
TotalConsumptionDay {round( (ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Day&amp;quot;,&amp;quot;&amp;quot;) )/1000 ,2)},\&lt;br /&gt;
TotalConsumptionMonth {round( (ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Month&amp;quot;,&amp;quot;&amp;quot;) )/1000 ,2)},\&lt;br /&gt;
TotalConsumptionYear {round( (ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Year&amp;quot;,&amp;quot;&amp;quot;) )/1000,2)},\&lt;br /&gt;
\&lt;br /&gt;
AutarkyQuote {my $valA = ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;, &amp;quot;Total_AC_active_power&amp;quot;,&amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;, &amp;quot;Home_own_consumption_from_grid&amp;quot;,&amp;quot;&amp;quot;);;;; my $calcVal = ($valA &amp;gt; 0)?round($valA /($valA + ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;, &amp;quot;Home_own_consumption_from_grid&amp;quot;,&amp;quot;&amp;quot;))*100 ,0) : 0 ;;;; ($calcVal &amp;gt; 100)?100:$calcVal },\&lt;br /&gt;
AutarkyQuoteDay {round(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Autarky_Day&amp;quot;, &amp;quot;&amp;quot;),0)},\&lt;br /&gt;
AutarkyQuoteMonth {round(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Autarky_Month&amp;quot;, &amp;quot;&amp;quot;),0)},\&lt;br /&gt;
AutarkyQuoteYear {round(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_Autarky_Year&amp;quot;, &amp;quot;&amp;quot;),0)},\&lt;br /&gt;
\&lt;br /&gt;
SelfConsumptionQuote {my $valS = ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_AC_active_power&amp;quot;, 0) ;;;; my $calcVal = ($valS &amp;gt; 0)?round((ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_PV&amp;quot;, &amp;quot;0&amp;quot;) + ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_battery&amp;quot;,&amp;quot;0&amp;quot;)) / $valS * 100 ,0) : 0 ;;;; ($calcVal &amp;gt; 100)?100:$calcVal},\&lt;br /&gt;
SelfConsumptionQuoteDay {round(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_OwnConsumptionRate_Day&amp;quot;, &amp;quot;&amp;quot;),0)},\&lt;br /&gt;
SelfConsumptionQuoteMonth {round(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_OwnConsumptionRate_Month&amp;quot;, &amp;quot;&amp;quot;),0)},\&lt;br /&gt;
SelfConsumptionQuoteYear {round(ReadingsVal(&amp;quot;PV_Anlage_1_API&amp;quot;,&amp;quot;Statistic_OwnConsumptionRate_Year&amp;quot;, &amp;quot;&amp;quot;),0)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Erstellen von zusätzlichen Werten in der Datenbank ===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|900px|rechts|Die Definitiun diese Diagramms ist weiter unten beschrieben.]]&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft und werden dann später mal gelöscht.&lt;br /&gt;
==== RAW Definition LogDBRep_PV_total_diff_Week ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_total_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week device Dum.Energy&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week reading PVTotalMonth&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition LogDBRep_PV_total_max_Month ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_total_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_total_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_total_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_PV_total_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_total_max_Month device Dum.Energy&lt;br /&gt;
attr LogDBRep_PV_total_max_Month reading PVTotalMonth&lt;br /&gt;
attr LogDBRep_PV_total_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_PV_total_max_Month timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_PV_total_max_Month timestamp_end previous_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition LogDBRep_PV_used_diff_Week ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_used_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week device Dum.Energy&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week reading PVMonth&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition LogDBRep_PV_used_max_Month ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_used_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_used_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_used_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_PV_used_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_used_max_Month device Dum.Energy&lt;br /&gt;
attr LogDBRep_PV_used_max_Month reading PVMonth&lt;br /&gt;
attr LogDBRep_PV_used_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_PV_used_max_Month timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_PV_used_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Timing für die Datenbank Einträge ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DF_DB_Service DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))(\&lt;br /&gt;
  set LogDBRep_PV_used_max_Month maxValue writeToDB;;\&lt;br /&gt;
  set LogDBRep_PV_total_max_Month maxValue writeToDB\&lt;br /&gt;
  )\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))(\&lt;br /&gt;
  set LogDBRep_PV_used_diff_Week diffValue writeToDB;;\&lt;br /&gt;
  set LogDBRep_PV_total_diff_Week diffValue writeToDB\&lt;br /&gt;
  )\&lt;br /&gt;
&lt;br /&gt;
attr DF_DB_Service DbLogExclude .*&lt;br /&gt;
attr DF_DB_Service do always&lt;br /&gt;
attr DF_DB_Service room System&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Löschen von nicht mehr benötigten Werten in der Datenbank ===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen trend erkennen lassen.&lt;br /&gt;
Wen eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wetter-/Leistungs-Prognose ==&lt;br /&gt;
Dies ist ein Thema, dass nicht wirklich gut zu fassen ist und ist eher etwas für Enthusiasten :-), wer schon mal mit Sonne, Wolken und Regen gerechnet hat versteht was ich meine. Dieser Ansatz ist nicht wissenschaftlicher Art und hat auch keinen Anspruch mathematischer Perfektion. Nach reinem Gefühl und mit aus dem Fenster schauen kommt jedoch ein respektables Ergebnis dabei heraus. Viel Vergnügen und Spaß beim mitbasteln ;-)&lt;br /&gt;
[[Bild:Plenticore_Forecast_Tagesanfang.png|mini|900px|rechts|Wenn der Tag begonnen hat ist die Prognose vom Vortag bereits im Diagramm. Der Wert Calculation in schwarz ist die aktuelle Korrektur.]]&lt;br /&gt;
=== Deutscher Wetter Dienst (DWD) ===&lt;br /&gt;
Der DWD liefert über Mosmix kostenlos, stunden aktuelle Prognosedaten. Über einen Link am Ende dieser Seite kommt man zum &amp;quot;Photovoltaikforum&amp;quot;, wo dieses Thema erarbeitet wurde, weshalb ich es hier nicht wiederholen möchte.&lt;br /&gt;
Über Mosmix werden für diese Anwendung die Werte Rad1h und TTT bezogen, was der globalen Sonneneinstrahlung und der Temperatur entspricht.&lt;br /&gt;
Die Daten werden ins Gerät &amp;quot;DWD_Prognose&amp;quot; in das reading &amp;quot;output&amp;quot; als JSON String geschrieben und dort in readings ausgepackt.&lt;br /&gt;
Der Trigger erfolgt über das DOIF PV_Schedule , die Abholzeiten muss man noch auf die eigenen Belange anpassen, damit man nicht abholt bevor die Daten vom DWD bereit stehen. Hier gibt es oftmals Verzögerungen von über einer Stunde, was man auf dem FTP Server am Zeitstempel sehen kann. Auch hier bitte nicht zu oft abholen, damit die Server nicht überlastet werden.&lt;br /&gt;
==== Daten abholen und auspacken ====&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ cat dwd_get_forecast.py &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
#  Copyright (C) 2020  Kilian Knoll kilian.knoll@gmx.de&lt;br /&gt;
#  &lt;br /&gt;
#  This program is free software: you can redistribute it and/or modify&lt;br /&gt;
#  it under the terms of the GNU General Public License as published by&lt;br /&gt;
#  the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
#  (at your option) any later version.&lt;br /&gt;
#&lt;br /&gt;
#  This program is distributed in the hope that it will be useful,&lt;br /&gt;
#  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
#  GNU General Public License for more details.&lt;br /&gt;
#&lt;br /&gt;
#  You should have received a copy of the GNU General Public License&lt;br /&gt;
#  along with this program.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
#&lt;br /&gt;
# Purpose &lt;br /&gt;
#Extract weather forecast data from DWD Mosmix for a given Station ID&lt;br /&gt;
#&lt;br /&gt;
# Background information:&lt;br /&gt;
# DWD provides 10 day forecast weather - and radiation data at an hourly resolution for over 5000 Stations worldwide (focus is on Germany/Europe though...)&lt;br /&gt;
# Description of kml file:&lt;br /&gt;
#https://www.dwd.de/DE/leistungen/opendata/help/schluessel_datenformate/kml/mosmix_elemente_pdf.pdf?__blob=publicationFile&amp;amp;v=3&lt;br /&gt;
#&lt;br /&gt;
#List of available stations:&lt;br /&gt;
#https://www.dwd.de/DE/leistungen/met_verfahren_mosmix/mosmix_stationskatalog.cfg?view=nasPublication&amp;amp;nn=495490&lt;br /&gt;
#&lt;br /&gt;
# How to use this ?&lt;br /&gt;
# 1) Find the station close by your geographic location:&lt;br /&gt;
#   Go to the website below, zoom to your location - and click on &amp;quot;Mosmix Stationen anzeigen&amp;quot; &lt;br /&gt;
#   Once you found the closest station, please change the station number to  the station number &lt;br /&gt;
#   https://wettwarn.de/mosmix/mosmix.html&lt;br /&gt;
#   In my case, I picked Station P755 (which is close to Munich)&lt;br /&gt;
# 2) Make changes in code below to reflect your station number - and the corresponding URL&lt;br /&gt;
#   change&lt;br /&gt;
#       self.mystation = P755&lt;br /&gt;
#   below to the one you identified during step 1&lt;br /&gt;
#   change the URL further down below to reflect the station:&lt;br /&gt;
# self.urlpath = &#039;https://opendata.dwd.de/weather/local_forecasts/mos/MOSMIX_L/single_stations/P755/kml&#039; &lt;br /&gt;
# Your one time setup is done...&lt;br /&gt;
# &lt;br /&gt;
# Implementation&lt;br /&gt;
# DWD provides two types of kml files&lt;br /&gt;
# single station kml files. These get updated approx every 6 hours&lt;br /&gt;
# all stations. These get updated hourly. However the file is pretty large. On embedded systems such as raspberry pi, I ran out of memory trying to parse XML files that size (exceeded 1GB of memory). Hence the decision to use the single station files&lt;br /&gt;
# we are only looking for a couple of key parameters that are relevant &lt;br /&gt;
#Currently the following Parameters get extracted from the kml file and put into a twodimensional array:&lt;br /&gt;
#mytimestamp : Timestamp of the forecast  data&lt;br /&gt;
#Rad1h       : Radiation Energy [kj/m²]&lt;br /&gt;
#TTT         : Temperature 2 m above surface [°C]&lt;br /&gt;
#PPPP        : Presssure Values (Surface Pressure reduced)&lt;br /&gt;
#FF          : Wind speed [m/s]&lt;br /&gt;
# &lt;br /&gt;
# &lt;br /&gt;
# Update August 05 2020&lt;br /&gt;
# Kilian did a lot of perfect prework, but I did some cleanup on this code. Originally it was written for a different environment.&lt;br /&gt;
# The changes are related to the communication with FHEM and the code is triggered also by FHEM for a one time run each call.&lt;br /&gt;
# Unnessesary data is dropped, to reduce the amount of data transfered to FHEM&lt;br /&gt;
&lt;br /&gt;
import urllib.request&lt;br /&gt;
import shutil&lt;br /&gt;
import zipfile&lt;br /&gt;
from bs4 import BeautifulSoup&lt;br /&gt;
import requests&lt;br /&gt;
import xml.etree.ElementTree as ET&lt;br /&gt;
import time&lt;br /&gt;
import datetime&lt;br /&gt;
import queue&lt;br /&gt;
import threading&lt;br /&gt;
import logging&lt;br /&gt;
import pprint&lt;br /&gt;
&lt;br /&gt;
import fhem&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
web     = sys.argv[1]&lt;br /&gt;
station = sys.argv[2]&lt;br /&gt;
&lt;br /&gt;
pp = pprint.PrettyPrinter(indent=4)&lt;br /&gt;
&lt;br /&gt;
def connvertINTtimestamptoDWD(inputstring):&lt;br /&gt;
    # Purpose: Convert a timestamp as presented by the UTC: 1545030000.0&lt;br /&gt;
    # and return it to a UTC representation: 2018-12-17T08:00:00.000000Z&lt;br /&gt;
    #mynewtime =time.mktime(datetime.datetime.strptime(inputstring, &amp;quot;%Y-%m-%dT%H:%M:%S.%fZ&amp;quot;).timetuple())&lt;br /&gt;
    #print (&amp;quot;neue Zeit &amp;quot;, mynewtime)&lt;br /&gt;
    mysecondtime = (datetime.datetime.fromtimestamp(inputstring).strftime(&#039;%Y-%m-%dT%H:%M:%S.%f&#039;)[:-3]) + &amp;quot;Z&amp;quot;     &lt;br /&gt;
    return (mysecondtime)  &lt;br /&gt;
&lt;br /&gt;
# Main class that holds the required information &lt;br /&gt;
class dwdforecast(threading.Thread):&lt;br /&gt;
    def __init__ (self, myqueue):&lt;br /&gt;
        print (&amp;quot;Starting dwdforecast init ...&amp;quot;)&lt;br /&gt;
        self.myqueue = myqueue&lt;br /&gt;
        self.event = threading.Event()&lt;br /&gt;
        self.ext = &#039;kmz&#039;&lt;br /&gt;
        self.mystation = station                            # This should be your closes station&lt;br /&gt;
        # Only use the &amp;quot;all_stations&amp;quot; if you got decent hardware&lt;br /&gt;
        #self.urlpath = &#039;http://opendata.dwd.de/weather/local_forecasts/mos/MOSMIX_S/all_stations/kml&#039;&lt;br /&gt;
        #On Raspberries &amp;amp; alikes, use the one for your specific station: &lt;br /&gt;
        self.urlpath = &#039;https://opendata.dwd.de/weather/local_forecasts/mos/MOSMIX_L/single_stations/&#039; + self.mystation +&#039;/kml&#039;&lt;br /&gt;
        self.lasttimecheck = 1534800680.0                   # Dec 14th 2018 (pure initialization)&lt;br /&gt;
        self.sleeptime = 15                                 #Time interval we poll the server [seconds]- please increase time since updates from DWD are hourly at best&lt;br /&gt;
        self.myinit = 0                                                                                     #So we can populate the queue initially / subsequently&lt;br /&gt;
        threading.Thread.__init__ (self)&lt;br /&gt;
        print (&amp;quot;I am looking for data from DWD for the following station: &amp;quot;, self.mystation)&lt;br /&gt;
        print (&amp;quot;I will be polling the following URL for the latest updates &amp;quot;, self.urlpath)&lt;br /&gt;
&lt;br /&gt;
    # Based on the user specified URL, find the latest file file with it´s timestamp &lt;br /&gt;
    def GetURLForLatest(self,urlpath, ext=&#039;&#039;):&lt;br /&gt;
        try:&lt;br /&gt;
            page = requests.get(urlpath).text&lt;br /&gt;
        except Exception as ErrorGetWebdata:&lt;br /&gt;
            logging.error(&amp;quot;%s %s&amp;quot;,&amp;quot;,GetURLForLatest Error getting data from the internet:&amp;quot;, ErrorGetWebdata)&lt;br /&gt;
        soup = BeautifulSoup(page, &#039;html.parser&#039;)&lt;br /&gt;
        soup_reduced= soup.find_all(&#039;pre&#039;)&lt;br /&gt;
        soup_reduced = soup_reduced[0]&lt;br /&gt;
        counter = 0&lt;br /&gt;
        for elements in soup_reduced:&lt;br /&gt;
            elements = str(elements)&lt;br /&gt;
            if (counter &amp;gt;0):&lt;br /&gt;
                words =elements.split()&lt;br /&gt;
                mytime = words[0] +&amp;quot;-&amp;quot; + words[1]&lt;br /&gt;
                logging.debug(&amp;quot;%s %s&amp;quot; ,&amp;quot;,GetURLForLatest :DWD Filetimestamp found :&amp;quot;, mytime)&lt;br /&gt;
                mynewtime =time.mktime(datetime.datetime.strptime(mytime, &amp;quot;%d-%b-%Y-%H:%M&amp;quot;).timetuple())&lt;br /&gt;
                logging.debug(&amp;quot;%s %s&amp;quot; ,&amp;quot;,GetURLForLatest :DWD Filetimestamp found :&amp;quot;, mynewtime)&lt;br /&gt;
                #print (&amp;quot;From function GetURLForLatest -mynewtime&amp;quot;, 2*mynewtime)&lt;br /&gt;
            &lt;br /&gt;
            if (elements.find(&amp;quot;LATEST&amp;quot;) &amp;gt;0):&lt;br /&gt;
                #print (&amp;quot;My element&amp;quot;, elements)&lt;br /&gt;
                counter = 1&lt;br /&gt;
        myurl = [urlpath + &#039;/&#039; + node.get(&#039;href&#039;) for node in soup.find_all(&#039;a&#039;) if node.get(&#039;href&#039;).endswith(ext)]&lt;br /&gt;
        return (myurl, mynewtime)&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
    def connvertDWDtimestamptoINT(self,inputstring):&lt;br /&gt;
        # Purpose: Convert a timestamp as presented by the DWD: 2018-12-25T07:00:00.000Z&lt;br /&gt;
        # and return it to a UTC representation&lt;br /&gt;
        mynewtime =time.mktime(datetime.datetime.strptime(inputstring, &amp;quot;%Y-%m-%dT%H:%M:%S.%fZ&amp;quot;).timetuple())&lt;br /&gt;
        #print (&amp;quot;neue Zeit &amp;quot;, mynewtime)&lt;br /&gt;
        #mysecondtime = datetime.datetime.fromtimestamp(mynewtime).strftime(&#039;%Y-%m-%dT%H:%M:%S.%fZ&#039;)     &lt;br /&gt;
        #print (&amp;quot;Einmal retour&amp;quot;, mysecondtime)&lt;br /&gt;
        mycurrentINTtimestamp =int(mynewtime)&lt;br /&gt;
        return (mycurrentINTtimestamp)&lt;br /&gt;
   &lt;br /&gt;
    &lt;br /&gt;
    def connvertDWDtimestamptoINT(self,inputstring):&lt;br /&gt;
        # Purpose: Convert a timestamp as presented by the DWD: 2018-12-25T07:00:00.000Z&lt;br /&gt;
        # and return it to a UTC representation&lt;br /&gt;
        mynewtime =time.mktime(datetime.datetime.strptime(inputstring, &amp;quot;%Y-%m-%dT%H:%M:%S.%fZ&amp;quot;).timetuple())&lt;br /&gt;
        mycurrentINTtimestamp =int(mynewtime)&lt;br /&gt;
        return (mycurrentINTtimestamp)&lt;br /&gt;
 &lt;br /&gt;
    try:&lt;br /&gt;
        def run(self):&lt;br /&gt;
            if (self.myinit== 0):                 #We populate the first timestamp to signal to main that we are up &amp;amp; running&lt;br /&gt;
                temptimestamp = time.time()&lt;br /&gt;
                print (&amp;quot;From dwdforecast - initial queue population&amp;quot;, temptimestamp)&lt;br /&gt;
                self.myqueue.put(temptimestamp)&lt;br /&gt;
                self.myinit = 1&lt;br /&gt;
            time.sleep(1)&lt;br /&gt;
            try:&lt;br /&gt;
                self.mydownloadfiles, self.mynewtime = self.GetURLForLatest(self.urlpath, self.ext)&lt;br /&gt;
                #print (&amp;quot;Downloadfiles = &amp;quot;, self.mydownloadfiles)&lt;br /&gt;
                #print (&amp;quot;Timestamp    = &amp;quot;, self.mynewtime)&lt;br /&gt;
            except Exception as ErrorReadFromDWD:&lt;br /&gt;
                logging.error(&amp;quot;%s %s&amp;quot; ,&amp;quot;,dwdforecast  :&amp;quot;, ErrorReadFromDWD)&lt;br /&gt;
            &lt;br /&gt;
            self.myarray =[]&lt;br /&gt;
            for self.file in self.mydownloadfiles:&lt;br /&gt;
                self.myarray.append(self.file)&lt;br /&gt;
            self.temp_length = len(self.myarray)&lt;br /&gt;
            self.url = self.myarray[self.temp_length-1]&lt;br /&gt;
&lt;br /&gt;
            logging.debug(&amp;quot;%s %s %s&amp;quot;,&amp;quot;,dwdforecast : -BEFORE  if- time comparison :&amp;quot;, self.mynewtime, self.lasttimecheck)                &lt;br /&gt;
#              if (self.mynewtime &amp;gt; self.lasttimecheck):&lt;br /&gt;
            logging.debug(&amp;quot;%s %s %s&amp;quot; ,&amp;quot;,dwdforecast : -in if- time comparison :&amp;quot;, self.mynewtime, self.lasttimecheck)&lt;br /&gt;
            #print (&amp;quot;DWD Weather - we have found a new kml file that we will download - timestamp was :&amp;quot;, self.mynewtime)&lt;br /&gt;
            #print (&amp;quot;DWD Weather -  self.lasttimecheck was &amp;quot;, self.lasttimecheck)&lt;br /&gt;
            self.lasttimecheck = self.mynewtime&lt;br /&gt;
            self.file_name = &amp;quot;dwd_temp1.gz&amp;quot;&lt;br /&gt;
            self.out_file = &amp;quot;dwd_temp2.gz&amp;quot;&lt;br /&gt;
            self.targetdir =&amp;quot;./&amp;quot;&lt;br /&gt;
            try:&lt;br /&gt;
                    time.sleep(10)                                          #Assumption is - we see the file on the DWD server - but it has not yet been copied over&lt;br /&gt;
                    # Download the file from `url` and save it locally under `self.file_name`:&lt;br /&gt;
                    with urllib.request.urlopen(self.url) as self.response, open(self.file_name, &#039;wb&#039;) as self.out_file:&lt;br /&gt;
                        shutil.copyfileobj(self.response, self.out_file)&lt;br /&gt;
                    time.sleep(5)                                           #not sure if this gets rid of the access problems                  &lt;br /&gt;
                    with zipfile.ZipFile(self.file_name,&amp;quot;r&amp;quot;) as zip_ref:&lt;br /&gt;
                        Myzipfilename = (zip_ref.namelist())&lt;br /&gt;
                        Myzipfilename = str(Myzipfilename[0])&lt;br /&gt;
                        zip_ref.extractall(self.targetdir)    &lt;br /&gt;
                    logging.debug(&amp;quot;%s %s&amp;quot; ,&amp;quot;,dwdforecast : -File that I extract is zipfile :&amp;quot;, Myzipfilename)&lt;br /&gt;
                    time.sleep(5)                                           #not sure if this gets rid of the access problems&lt;br /&gt;
            except Exception as MyException:&lt;br /&gt;
                    logging.error(&amp;quot;%s %s&amp;quot;, &amp;quot;,subroutine dwdforecast exception getting the data from server : &amp;quot;, MyException)    &lt;br /&gt;
                        &lt;br /&gt;
            self.tree = ET.parse(Myzipfilename) &lt;br /&gt;
            self.root = self.tree.getroot()&lt;br /&gt;
            self.root.tag     &lt;br /&gt;
            &amp;quot;&amp;quot;&amp;quot;      &lt;br /&gt;
            &amp;lt;kml:kml xmlns:dwd=&amp;quot;https://opendata.dwd.de/weather/lib/pointforecast_dwd_extension_V1_0.xsd&amp;quot; xmlns:gx=&amp;quot;http://www.google.com/kml/ext/2.2&amp;quot; xmlns:xal=&amp;quot;urn:oasis:names:tc:ciq:xsdschema:xAL:2.0&amp;quot; xmlns:kml=&amp;quot;http://www.opengis.net/kml/2.2&amp;quot; xmlns:atom=&amp;quot;http://www.w3.org/2005/Atom&amp;quot;&amp;gt;&lt;br /&gt;
                        &lt;br /&gt;
            &amp;lt;kml:kml xmlns:dwd=&amp;quot;https://opendata.dwd.de/weather/lib/pointforecast_dwd_extension_V1_0.xsd&amp;quot; xmlns:gx=&amp;quot;http://www.google.com/kml/ext/2.2&amp;quot; xmlns:xal=&amp;quot;urn:oasis:names:tc:ciq:xsdschema:xAL:2.0&amp;quot; xmlns:kml=&amp;quot;http://www.opengis.net/kml/2.2&amp;quot; xmlns:atom=&amp;quot;http://www.w3.org/2005/Atom&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
            #--------------------------------------------------&lt;br /&gt;
            #Namespace definition for kml file:&lt;br /&gt;
            #&lt;br /&gt;
            self.ns = {&#039;dwd&#039;: &#039;https://opendata.dwd.de/weather/lib/pointforecast_dwd_extension_V1_0.xsd&#039;, &#039;gx&#039;: &#039;http://www.google.com/kml/ext/2.2&#039;,&lt;br /&gt;
            &#039;kml&#039;: &#039;http://www.opengis.net/kml/2.2&#039;, &#039;atom&#039;: &#039;http://www.w3.org/2005/Atom&#039;, &#039;xal&#039;:&#039;urn:oasis:names:tc:ciq:xsdschema:xAL:2.0&#039;}&lt;br /&gt;
                #--------------------------------------------------&lt;br /&gt;
                # We get the timestamps&lt;br /&gt;
                #&lt;br /&gt;
            self.timestamps = self.root.findall(&#039;kml:Document/kml:ExtendedData/dwd:ProductDefinition/dwd:ForecastTimeSteps/dwd:TimeStep&#039;,self.ns)&lt;br /&gt;
            self.i = 0&lt;br /&gt;
            self.timevalue=[]&lt;br /&gt;
            for self.child in self.timestamps:&lt;br /&gt;
                #print (&amp;quot;TIMESTAMPS&amp;quot;,  child.text)&lt;br /&gt;
                self.timevalue.append(self.child.text)&lt;br /&gt;
            &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
            for j in timevalue:&lt;br /&gt;
                print (&amp;quot;Zeit&amp;quot;,i, &amp;quot; &amp;quot;, timevalue[i])&lt;br /&gt;
                i = i+1&lt;br /&gt;
            &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
                        &lt;br /&gt;
            for self.elem in self.tree.findall(&#039;./kml:Document/kml:Placemark&#039;,self.ns):                    #Position us at the Placemark&lt;br /&gt;
                #print (&amp;quot;SUCERJH &amp;quot;, sucher)&lt;br /&gt;
                #print (&amp;quot;Elemente &amp;quot;, elem.tag, elem.attrib, elem.text)&lt;br /&gt;
                self.mylocation = self.elem.find(&#039;kml:name&#039;,self.ns).text                                  #Look for the station Number&lt;br /&gt;
                        &lt;br /&gt;
                # Hier IF Frage einbauen&lt;br /&gt;
                if (self.mylocation == self.mystation):   &lt;br /&gt;
                    #print (&amp;quot;meine location&amp;quot;, self.mylocation)&lt;br /&gt;
                    self.myforecastdata = self.elem.find(&#039;kml:ExtendedData&#039;,self.ns)&lt;br /&gt;
                    for self.elem in self.myforecastdata:                                         &lt;br /&gt;
                        #We may get the following strings and are only interested in the right hand quoted property name WPcd1:&lt;br /&gt;
                        #{&#039;{https://opendata.dwd.de/weather/lib/pointforecast_dwd_extension_V1_0.xsd}elementName&#039;: &#039;WPcd1&#039;}&lt;br /&gt;
                        self.trash = str(self.elem.attrib)&lt;br /&gt;
                        self.trash1,self.mosmix_element = self.trash.split(&amp;quot;&#039;: &#039;&amp;quot;)&lt;br /&gt;
                        self.mosmix_element, self.trash = self.mosmix_element.split(&amp;quot;&#039;}&amp;quot;)&lt;br /&gt;
                        #-------------------------------------------------------------&lt;br /&gt;
                        # Currently looking at the following key Data:&lt;br /&gt;
                        # Looking for the following mosmix_elements &lt;br /&gt;
                        #FF : Wind Speed            [m/s]&lt;br /&gt;
                        #Rad1h : Global irridance   [kJ/m²]&lt;br /&gt;
                        #TTT : Temperature 2m above ground [Kelvin]&lt;br /&gt;
                        #PPPP : Pressure reduced    [Pa]&lt;br /&gt;
                        #-------------------------------------------------------------&lt;br /&gt;
                        if (&#039;FF&#039; == self.mosmix_element):&lt;br /&gt;
                            self.FF_temp = self.elem[0].text&lt;br /&gt;
                            self.FF = list (self.FF_temp.split())&lt;br /&gt;
                        if (&#039;Rad1h&#039; == self.mosmix_element):&lt;br /&gt;
                            self.Rad1h_temp = self.elem[0].text&lt;br /&gt;
                            self.Rad1h = list (self.Rad1h_temp.split())&lt;br /&gt;
                        if (&#039;TTT&#039; == self.mosmix_element):&lt;br /&gt;
                            self.TTT_temp = self.elem[0].text&lt;br /&gt;
                            self.TTT = list(self.TTT_temp.split())&lt;br /&gt;
                            counter = 0 &lt;br /&gt;
                            # We convert from Kelvin to Celcius...:&lt;br /&gt;
                            for i in self.TTT:&lt;br /&gt;
                                self.TTT[counter]=round((float(self.TTT[counter])-273.13),2)&lt;br /&gt;
                                #print (self.TTT[counter])&lt;br /&gt;
                                counter = counter +1&lt;br /&gt;
                        if (&#039;PPPP&#039; == self.mosmix_element):&lt;br /&gt;
                            self.PPPP_temp = self.elem[0].text&lt;br /&gt;
                            self.PPPP = list (self.PPPP_temp.split())&lt;br /&gt;
                    &lt;br /&gt;
                    &lt;br /&gt;
                    #------------------------------------&lt;br /&gt;
                    # Define empty array                &lt;br /&gt;
                self.mosmixdata =[]&lt;br /&gt;
                for self.j in range(6):                                      #Right now we have timevalue, mytimestamp, self.FF Rad1h TTT PPPP&lt;br /&gt;
                    self.column = []&lt;br /&gt;
                    self.counter = 0&lt;br /&gt;
                    for self.i in self.timevalue:&lt;br /&gt;
                        self.column.append(0)&lt;br /&gt;
                    self.mosmixdata.append(self.column)&lt;br /&gt;
                    #------------------------------------&lt;br /&gt;
                    #Populate values&lt;br /&gt;
                counter = 0&lt;br /&gt;
                    &lt;br /&gt;
                for self.i in self.timevalue:&lt;br /&gt;
                    self.mytimestamp = self.connvertDWDtimestamptoINT(self.timevalue[counter])&lt;br /&gt;
                    self.mosmixdata[0][counter]=self.timevalue[counter]&lt;br /&gt;
                    self.mosmixdata[1][counter]=self.mytimestamp&lt;br /&gt;
                    self.mosmixdata[2][counter]=self.Rad1h[counter]&lt;br /&gt;
                    self.mosmixdata[3][counter]=self.TTT[counter]&lt;br /&gt;
                    self.mosmixdata[4][counter]=self.PPPP[counter]&lt;br /&gt;
                    self.mosmixdata[5][counter]=self.FF[counter]&lt;br /&gt;
                    counter = counter + 1&lt;br /&gt;
                    #------------------------------------------&lt;br /&gt;
&lt;br /&gt;
            self.cols = len(self.mosmixdata)&lt;br /&gt;
            rows = 0&lt;br /&gt;
            if self.cols:&lt;br /&gt;
                self.rows = len(self.mosmixdata[0])&lt;br /&gt;
            self.MosmixFileFirsttimestamp = self.mosmixdata[1][0]&lt;br /&gt;
                #print (&amp;quot;My first stamp from the file is:&amp;quot;,self.mosmixdata[0][0],&amp;quot;Endstring&amp;quot;,self.mosmixdata[1][0] )       &lt;br /&gt;
                #print (&amp;quot;-------------------------------------------------&amp;quot;)&lt;br /&gt;
                #print (self.mosmixdata)&lt;br /&gt;
            self.indexcounter_addrows=1&lt;br /&gt;
            self.MyWeathervalues = {}&lt;br /&gt;
            try:&lt;br /&gt;
                print (&amp;quot;Here is what we got from DWD :&amp;quot;)&lt;br /&gt;
                for j in range(self.rows):&lt;br /&gt;
                    if (self.indexcounter_addrows &amp;gt;0):                                       #We are adding from the point onward - see self.indexcounter_addrows if check below&lt;br /&gt;
                        #print (&amp;quot;counting indices&amp;quot;, self.indexcounter_addrows)&lt;br /&gt;
                        #self.MyWeathervalues.update({&#039;mydatetime&#039;:self.mosmixdata[0][j]})&lt;br /&gt;
                        #self.MyWeathervalues.update({&#039;mytimestamp&#039;:self.mosmixdata[1][j]})&lt;br /&gt;
                        if (self.mosmixdata[2][j] &amp;gt; &#039;0.00&#039;):                                 #Reduce unneccessary data&lt;br /&gt;
                            self.time = time.strftime(&amp;quot;%Y-%m-%d_%H:%M&amp;quot;, time.localtime(self.mosmixdata[1][j]))&lt;br /&gt;
                            self.MyWeathervalues.update({self.time + &#039;_Rad1wh&#039;:int(round(float(self.mosmixdata[2][j]) * 0.277778 , 0))})&lt;br /&gt;
                            self.MyWeathervalues.update({self.time + &#039;_TTT&#039;:self.mosmixdata[3][j]})&lt;br /&gt;
                        #self.MyWeathervalues.update({&#039;TTT&#039;:self.mosmixdata[3][j]})&lt;br /&gt;
                        #self.MyWeathervalues.update({&#039;PPPP&#039;:self.mosmixdata[4][j]})&lt;br /&gt;
                        #self.MyWeathervalues.update({&#039;FF&#039;:self.mosmixdata[5][j]})  &lt;br /&gt;
&lt;br /&gt;
                        #print (&#039;mydatetime&#039;,self.mosmixdata[0][j],&#039;mytimestamp &#039;,self.mosmixdata[1][j],&#039;Rad1h &#039;,self.mosmixdata[2][j],&#039;TTT &#039;,self.mosmixdata[3][j], &#039;PPPP&#039;,self.mosmixdata[4][j],&#039;FF&#039;,self.mosmixdata[5][j])&lt;br /&gt;
&lt;br /&gt;
                import re&lt;br /&gt;
                self.message = re.sub(&amp;quot;&#039;&amp;quot;, &amp;quot;\&amp;quot;&amp;quot;, str(self.MyWeathervalues))&lt;br /&gt;
                #print(self.MyWeathervalues)&lt;br /&gt;
                #print(self.message)&lt;br /&gt;
&lt;br /&gt;
                try:&lt;br /&gt;
                    with open(&#039;/opt/fhem/python/pwd_fhem.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
                        credentials=json.load(f)&lt;br /&gt;
                except Exception as e:&lt;br /&gt;
                    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
                fh = fhem.Fhem(web, protocol=&amp;quot;http&amp;quot;, port=8083, username=credentials[&amp;quot;username&amp;quot;], password=credentials[&amp;quot;password&amp;quot;])&lt;br /&gt;
&lt;br /&gt;
                fh.send_cmd(&amp;quot;setreading DWD_Prognose output &amp;quot; + self.message)&lt;br /&gt;
&lt;br /&gt;
                        &lt;br /&gt;
                self.mytimestamp = connvertINTtimestamptoDWD(self.mynewtime)&lt;br /&gt;
                logging.debug (&amp;quot;%s %s %s %s&amp;quot;, &amp;quot;,Subroutine dwdforecast -we have used DWD file from time : &amp;quot;, self.mynewtime, &amp;quot; &amp;quot;, self.mytimestamp)&lt;br /&gt;
            except Exception as ErrorDWDArray:&lt;br /&gt;
                print (&amp;quot;Shit happened  ?&amp;quot;, ErrorDWDArray)&lt;br /&gt;
                logging.error (&amp;quot;%s %s&amp;quot;, &amp;quot;,subroutine dwdforecast final exception : &amp;quot;, ErrorDWDArray)&lt;br /&gt;
            logging.debug(&amp;quot;%s %s&amp;quot;, &amp;quot;From dwdforecast - we have found a true commit and have updated the database at the following dwd time :&amp;quot;, self.mynewtime)&lt;br /&gt;
            time.sleep(self.sleeptime)          # We are putting in a sleep &lt;br /&gt;
            self.myqueue.put(self.mynewtime)&lt;br /&gt;
&lt;br /&gt;
    except Exception as ExceptionError:&lt;br /&gt;
            print (&amp;quot;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;quot;)&lt;br /&gt;
            print (&amp;quot;XXX-Aus Subroutine dwdforecast -verrant ? &amp;quot;, ExceptionError)&lt;br /&gt;
            print (&amp;quot;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;quot;)&lt;br /&gt;
            logging.error(&amp;quot;%s %s&amp;quot;, &amp;quot;,subroutine dwdforecast final exception : &amp;quot;, ExceptionError)&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
    logging.basicConfig(filename=&amp;quot;./log/dwd_debug.txt&amp;quot;,level=logging.DEBUG)&lt;br /&gt;
    #&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Interaction can be &#039;Simple&#039; - or &#039;Complex&#039;&lt;br /&gt;
    Simple : Try to get weather data once only - then terminate&lt;br /&gt;
    Complex : Start a seperate queue that continuously polls the DWD server on the internet to get updated data &lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Interaction = &#039;Simple&#039; #Interaction can be &#039;Simple&#039; - or &#039;Complex&#039;&lt;br /&gt;
    #&lt;br /&gt;
&lt;br /&gt;
    #-----------------------------------------------------------------&lt;br /&gt;
    # START Queue (To read dwd values and populate them to database):&lt;br /&gt;
    try:&lt;br /&gt;
        myQueue1 = queue.Queue()                                               &lt;br /&gt;
        myThread1= dwdforecast(myQueue1)                          &lt;br /&gt;
        myThread1.start()                                                             &lt;br /&gt;
        while myQueue1.empty():                                                  &lt;br /&gt;
            print(&amp;quot; Waiting on DWD dwdforecastdata Queue results to tell it is started...&amp;quot;)&lt;br /&gt;
            logging.info(&amp;quot;%s &amp;quot; &amp;quot;,Main :Waiting on Queue results to be populated ...&amp;quot;)&lt;br /&gt;
            time.sleep(1)&lt;br /&gt;
        # Queue End (To read values from DWD)&lt;br /&gt;
        #_________________________________________________________________&lt;br /&gt;
        i = 0 &lt;br /&gt;
            &lt;br /&gt;
        try:&lt;br /&gt;
            while i &amp;lt;1: &lt;br /&gt;
                if not myQueue1.empty():                                      # Falls was in der Queue steht machen wir was&lt;br /&gt;
                    quelength = myQueue1.qsize()                               # Wenn da viele Werte angelaufen sind, nehmen wir jetzt einfach den Letzten&lt;br /&gt;
                    #print (&amp;quot;LAENGE der QUEUE -XXXXXXXXXXXXXXXXXXXXXXX : &amp;quot;, quelength) &lt;br /&gt;
                    logging.info(&amp;quot;%s %s &amp;quot; ,&amp;quot;,Main :Queue length is : &amp;quot;, quelength) &lt;br /&gt;
                    &lt;br /&gt;
                    for x in range (0,quelength):&lt;br /&gt;
                        LastDWDtimestamp = myQueue1.get()                     # Das ist die magische Zeile in der wir den Wert aus der Queue abholen &lt;br /&gt;
                        mylasttimestamp = connvertINTtimestamptoDWD(LastDWDtimestamp)&lt;br /&gt;
                    print (&amp;quot;From Main : DWD File access I checked /  got uploaded by DWD was at :&amp;quot;, LastDWDtimestamp,mylasttimestamp )&lt;br /&gt;
                    i = i + 1&lt;br /&gt;
&lt;br /&gt;
        except Exception as OtherExceptionError:  &lt;br /&gt;
            print (&amp;quot;hit some other error....    !&amp;quot;, OtherExceptionError)&lt;br /&gt;
            &lt;br /&gt;
                &lt;br /&gt;
    except Exception as FinalExceptionError:  &lt;br /&gt;
        print (&amp;quot;I am clueless ... Hit some other error ....    !&amp;quot;, FinalExceptionError)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition DWD_Prognose ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DWD_Prognose expandJSON DWD_Prognose:output:.\{.*}&lt;br /&gt;
attr DWD_Prognose DbLogExclude .*&lt;br /&gt;
attr DWD_Prognose alias DWD_Prognose&lt;br /&gt;
attr DWD_Prognose comment Das Device wird über ein Python Skript im reading output befüllt.\&lt;br /&gt;
deletereading DWD_Prognose .*_Rad1wh\&lt;br /&gt;
&lt;br /&gt;
attr DWD_Prognose group PV Eigenverbrauch&lt;br /&gt;
attr DWD_Prognose icon measure_photovoltaic_inst&lt;br /&gt;
attr DWD_Prognose room Informationen-&amp;gt;Wetter,Strom-&amp;gt;Photovoltaik,Strom-&amp;gt;System&lt;br /&gt;
attr DWD_Prognose sortby 02&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== ProPlanta ===&lt;br /&gt;
Die Webseite Proplanta stellt unter anderem chOfRain*, cloud* in einer drei Stunden Prognose bereit und dies dann für mehrere Tage fc0 , fc1, ...&lt;br /&gt;
==== RAW Definition ProPlanta ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod ProPlanta PROPLANTA &amp;lt;Wohnort&amp;gt; de&lt;br /&gt;
attr ProPlanta DbLogExclude .*&lt;br /&gt;
attr ProPlanta DbLogInclude cloudBaseMax,cloudBaseMin,fc0_cloud06,fc0_cloud09,fc0_cloud12,fc0_cloud15,fc0_cloud18,fc0_rad,fc0_sun,fc0_uv,fc0_weather06,fc0_weather09,fc0_weather12,fc0_weather15,fc0_weather18,fc1_cloud06,fc1_cloud09,fc1_cloud12,fc1_cloud15,fc1_cloud18,fc1_rad,fc1_sun,fc1_uv,fc1_weather06,fc1_weather09,fc1_weather12,fc1_weather15,fc1_weather18,weather&lt;br /&gt;
attr ProPlanta INTERVAL 900&lt;br /&gt;
attr ProPlanta alias ProPlanta&lt;br /&gt;
attr ProPlanta event-on-change-reading cloudBaseMax,cloudBaseMin,fc0_cloud06,fc0_cloud09,fc0_cloud12,fc0_cloud15,fc0_cloud18,fc0_rad,fc0_sun,fc0_uv,fc0_weather06,fc0_weather09,fc0_weather12,fc0_weather15,fc0_weather18,fc1_cloud06,fc1_cloud09,fc1_cloud12,fc1_cloud15,fc1_cloud18,fc1_rad,fc1_sun,fc1_uv,fc1_weather06,fc1_weather09,fc1_weather12,fc1_weather15,fc1_weather18,weather&lt;br /&gt;
attr ProPlanta forecastDays 4&lt;br /&gt;
attr ProPlanta group ASC Environment&lt;br /&gt;
attr ProPlanta icon weather_sunrise&lt;br /&gt;
attr ProPlanta room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr ProPlanta sortby 02&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== myUtils.pm Funktionen ===&lt;br /&gt;
==== Solar_forecast ====&lt;br /&gt;
Achtung, diese Funktion ist noch nicht vollständig ausprogrammiert. Es wurden bereits Übergabeparameter integriert, um z.B. andere Wetterdienste zu berücksichtigen.&lt;br /&gt;
Um diese Funktion zu nutzen muss ein Dummy PV_Anlage_1_config vorhanden sein, in dem unter anderem die Modul und Anlagen Ausrichtung konfiguriert wird.&lt;br /&gt;
Rückfragen gerne im Forum.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
###########################################################&lt;br /&gt;
# Subroutine to calculate radiation&lt;br /&gt;
###########################################################&lt;br /&gt;
sub Solar_forecast($$$$$$$) {&lt;br /&gt;
&lt;br /&gt;
     my $logdb       = $_[0] ;&lt;br /&gt;
     my $logdbrep    = $_[1] ;        # Das wird zum Löschen in der LogDB verwendet und muss entsprechend konfiguriert sein.&lt;br /&gt;
     my $logdevice   = $_[2] ;&lt;br /&gt;
     # Hier könnte man noch andere Wetterdienste berücksichtigen bzw den Device Namen ändern&lt;br /&gt;
     my $wetter_1    = $_[4] ; if ($wetter_1 ne &amp;quot;DWD_Prognose&amp;quot;) {return(&amp;quot;$wetter_1 not supported&amp;quot;)} ;&lt;br /&gt;
     my $wetter_2    = $_[5] ; if ($wetter_2 ne &amp;quot;ProPlanta&amp;quot;   ) {return(&amp;quot;$wetter_2 not supported&amp;quot;)} ;&lt;br /&gt;
     my $fc          = $_[6] ;        # Wieviel Tage in die Zukunft soll es gehen? 0,1,2&lt;br /&gt;
     my $reading     = $_[3].$fc ;&lt;br /&gt;
&lt;br /&gt;
     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $year += 1900; $mon += 1;&lt;br /&gt;
     my ($Solar_Cloud,$Solar_Rain,$Solar_Temp,$Solar_SolarRadiation,$logentry,$i) = (0) x 6 ;&lt;br /&gt;
     my ($cloudk,$raink,$tempk,$cloudk_base,$raink_base,$tempk_base) = (0) x 6 ;&lt;br /&gt;
     my ($Solar_Correction_Cloud,$Solar_Correction_Rain,$Solar_Correction_Temp,$Solar_Plain) = (1) x 4 ;&lt;br /&gt;
     my (@Solar_,@module_count) = (0,0,0) ;&lt;br /&gt;
&lt;br /&gt;
     # Initialisieren des Basis TIMESTAMP für den Forecast&lt;br /&gt;
     my $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; 08:00:00&amp;quot;) ;&lt;br /&gt;
     my $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
     # Bei Forecast ab dem nächsten Tag zuerst die bisherigen Einträge für den Tag löschen&lt;br /&gt;
#     if ( $fc != 0 ) {&lt;br /&gt;
        fhem &amp;quot;set &amp;quot;.$logdbrep.&amp;quot; sqlCmd DELETE FROM history WHERE DEVICE=&#039;&amp;quot;.$logdevice.&amp;quot;&#039; AND READING=&#039;&amp;quot;.$reading.&amp;quot;&#039; AND TIMESTAMP&amp;gt;=&#039;&amp;quot;.$timestamp.&amp;quot;&#039;&amp;quot; ;&lt;br /&gt;
#     };&lt;br /&gt;
&lt;br /&gt;
      # Es werden Stundenwerte von 08:00 bis 19:00 Uhr berechnet&lt;br /&gt;
      for ($i = 8; $i &amp;lt;= 19; $i++) {&lt;br /&gt;
        $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; &amp;quot;.$i.&amp;quot;:00:00&amp;quot;) ;&lt;br /&gt;
        $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
        # Bei ProPlanta liegen die Werte im drei Stunden Abstand vor&lt;br /&gt;
        if ( $wetter_2 eq &amp;quot;ProPlanta&amp;quot;) {&lt;br /&gt;
          if ( $i &amp;gt;=  6 and $i &amp;lt;  9 )&lt;br /&gt;
            { $Solar_Cloud = ReadingsVal($wetter_2,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_cloud09&amp;quot;   ,0) ;&lt;br /&gt;
              $Solar_Rain  = ReadingsVal($wetter_2,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_chOfRain09&amp;quot;,0) ; } ;&lt;br /&gt;
          if ( $i &amp;gt;=  9 and $i &amp;lt; 12 )&lt;br /&gt;
            { $Solar_Cloud = ReadingsVal($wetter_2,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_cloud09&amp;quot;   ,0) ;&lt;br /&gt;
              $Solar_Rain  = ReadingsVal($wetter_2,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_chOfRain09&amp;quot;,0) ; } ;&lt;br /&gt;
          if ( $i &amp;gt;= 12 and $i &amp;lt; 15 )&lt;br /&gt;
            { $Solar_Cloud = ReadingsVal($wetter_2,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_cloud12&amp;quot;   ,0) ;&lt;br /&gt;
              $Solar_Rain  = ReadingsVal($wetter_2,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_chOfRain12&amp;quot;,0) ; } ;&lt;br /&gt;
          if ( $i &amp;gt;= 15 and $i &amp;lt; 18 )&lt;br /&gt;
            { $Solar_Cloud = ReadingsVal($wetter_2,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_cloud15&amp;quot;   ,0) ;&lt;br /&gt;
              $Solar_Rain  = ReadingsVal($wetter_2,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_chOfRain15&amp;quot;,0) ; } ;&lt;br /&gt;
         };&lt;br /&gt;
&lt;br /&gt;
        if ( $wetter_1 eq &amp;quot;DWD_Prognose&amp;quot;) {&lt;br /&gt;
          $Solar_Temp           = ReadingsVal($wetter_1,POSIX::strftime(&amp;quot;%Y-%m-%d_%H_00_TTT&amp;quot;,   localtime($timestring+($fc*24-1)*60*60)),0)+10;&lt;br /&gt;
          $Solar_SolarRadiation = ReadingsVal($wetter_1,POSIX::strftime(&amp;quot;%Y-%m-%d_%H_00_Rad1wh&amp;quot;,localtime($timestring+($fc*24-1)*60*60)),0) ;&lt;br /&gt;
         };&lt;br /&gt;
&lt;br /&gt;
        $cloudk = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
        if ($cloudk ne 0) {&lt;br /&gt;
          $cloudk_base = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk_base&amp;quot;,0) ;&lt;br /&gt;
          $Solar_Correction_Cloud = round((1 + ($Solar_Cloud - $cloudk_base) * $cloudk / 100),3) ;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        $raink  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink&amp;quot;,0) * -0.01 ;&lt;br /&gt;
        if ($raink ne 0) {&lt;br /&gt;
          $raink_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink_base&amp;quot; ,0) ;&lt;br /&gt;
          $Solar_Correction_Rain = round((1 + ($Solar_Rain  - $raink_base ) * $raink  / 100),3) ;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        $tempk  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
        if ($tempk ne 0) {&lt;br /&gt;
          $tempk_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk_base&amp;quot; ,0) ;&lt;br /&gt;
          $Solar_Correction_Temp = round((1 + ($Solar_Temp  - $tempk_base ) * $tempk  / 100),3) ;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        my $Solar_Correction_Faktor = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_factor&amp;quot;,1) ;&lt;br /&gt;
&lt;br /&gt;
        $logentry = 0 ;&lt;br /&gt;
        for(my $j=1;$j&amp;lt;4;$j++){&lt;br /&gt;
          $module_count[$j] = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_count&amp;quot;,0) ;&lt;br /&gt;
          if ($module_count[$j] ne 0) {&lt;br /&gt;
            $Solar_Plain = round(Solar_plain(ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0) , ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0) , $timestamp),3) ;&lt;br /&gt;
            Log 3, &amp;quot;plain/direction        :  &amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_plain&amp;quot;,0).&amp;quot;/&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_direction&amp;quot;,0).&amp;quot; &amp;gt;&amp;gt;&amp;gt; &amp;quot;.$Solar_Plain ;&lt;br /&gt;
            $Solar_[$j]  = $module_count[$j] * ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_power&amp;quot;,1)/1000 ;&lt;br /&gt;
            $Solar_[$j]  = $Solar_[$j] * $Solar_Plain ;&lt;br /&gt;
            $Solar_[$j]  = $Solar_[$j] * $Solar_SolarRadiation ;&lt;br /&gt;
            $Solar_[$j]  = $Solar_[$j] * $Solar_Correction_Temp * $Solar_Correction_Cloud * $Solar_Correction_Rain * $Solar_Correction_Faktor ;&lt;br /&gt;
            $Solar_[$j]  = ($Solar_[$j] lt 0)?0:round($Solar_[$j],0) ;&lt;br /&gt;
          };&lt;br /&gt;
          $logentry = $logentry + $Solar_[$j] ;&lt;br /&gt;
          if ($fc == 0 and $hour == $i) {&lt;br /&gt;
            fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_&amp;quot;.$j.&amp;quot;_name&amp;quot;,0).&amp;quot; &amp;quot;.$Solar_[$j] ;&lt;br /&gt;
          };&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        if ($fc == 0) {&lt;br /&gt;
          fhem &amp;quot;set &amp;quot;.$logdb.&amp;quot; addCacheLine &amp;quot;.$timestamp.&amp;quot;|&amp;quot;.$logdevice.&amp;quot;|addlog|&amp;quot;.$reading.&amp;quot;: &amp;quot;.$logentry.&amp;quot;|&amp;quot;.$reading.&amp;quot;|&amp;quot;.$logentry.&amp;quot;|&amp;quot;;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        if ($fc == 0 and $hour == $i and ($module_count[1] ne 0 or $module_count[2] ne 0 or $module_count[3] ne 0)) {&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_SolarRadiation &amp;quot;.$Solar_SolarRadiation ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Cloud &amp;quot;.$Solar_Cloud ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Rain &amp;quot;.$Solar_Rain ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Temp &amp;quot;.$Solar_Temp ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Correction_Cloud &amp;quot;.$Solar_Correction_Cloud ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Correction_Rain &amp;quot;.$Solar_Correction_Rain ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Correction_Temp &amp;quot;.$Solar_Correction_Temp ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Calculation &amp;quot;.$logentry ;&lt;br /&gt;
&lt;br /&gt;
          Log 3, &amp;quot;Solar_Plain            :  &amp;quot;.$Solar_Plain ;&lt;br /&gt;
          Log 3, &amp;quot;Solar_SolarRadiation   :  &amp;quot;.$Solar_SolarRadiation ;&lt;br /&gt;
          Log 3, &amp;quot;Solar_Cloud            :  &amp;quot;.$Solar_Cloud ;&lt;br /&gt;
          Log 3, &amp;quot;cloudk                 : &amp;quot;.$cloudk.&amp;quot; &amp;quot;.$cloudk_base ;&lt;br /&gt;
          Log 3, &amp;quot;Solar_Correction_Cloud :  &amp;quot;.$Solar_Correction_Cloud ;&lt;br /&gt;
          Log 3, &amp;quot;Solar_Rain             :  &amp;quot;.$Solar_Rain ;&lt;br /&gt;
          Log 3, &amp;quot;raink                  : &amp;quot;.$raink.&amp;quot; &amp;quot;.$raink_base ;&lt;br /&gt;
          Log 3, &amp;quot;Solar_Correction_Rain  :  &amp;quot;.$Solar_Correction_Rain ;&lt;br /&gt;
          Log 3, &amp;quot;Solar_Temp             :  &amp;quot;.$Solar_Temp ;&lt;br /&gt;
          Log 3, &amp;quot;tempk                  : &amp;quot;.$tempk.&amp;quot; &amp;quot;.$tempk_base ;&lt;br /&gt;
          Log 3, &amp;quot;Solar_Correction_Temp  :  &amp;quot;.$Solar_Correction_Temp ;&lt;br /&gt;
          Log 3, $fc.&amp;quot; &amp;quot;.$hour.&amp;quot; &amp;quot;.$i.&amp;quot; &amp;quot;.$Solar_SolarRadiation.&amp;quot; &amp;quot;.$logentry ;&lt;br /&gt;
        } ;&lt;br /&gt;
&lt;br /&gt;
        if ($fc != 0) {&lt;br /&gt;
          fhem &amp;quot;set &amp;quot;.$logdb.&amp;quot; addCacheLine &amp;quot;.$timestamp.&amp;quot;|&amp;quot;.$logdevice.&amp;quot;|addlog|&amp;quot;.$reading.&amp;quot;: &amp;quot;.$logentry.&amp;quot;|&amp;quot;.$reading.&amp;quot;|&amp;quot;.$logentry.&amp;quot;|&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
          Log 3, &amp;quot;Solar_Plain            :  &amp;quot;.$Solar_Plain ;&lt;br /&gt;
          Log 3, &amp;quot;Solar_SolarRadiation   :  &amp;quot;.$Solar_SolarRadiation ;&lt;br /&gt;
          Log 3, &amp;quot;Solar_Cloud            :  &amp;quot;.$Solar_Cloud ;&lt;br /&gt;
          Log 3, &amp;quot;cloudk                 : &amp;quot;.$cloudk.&amp;quot; &amp;quot;.$cloudk_base ;&lt;br /&gt;
          Log 3, &amp;quot;Solar_Correction_Cloud :  &amp;quot;.$Solar_Correction_Cloud ;&lt;br /&gt;
          Log 3, &amp;quot;Solar_Rain             :  &amp;quot;.$Solar_Rain ;&lt;br /&gt;
          Log 3, &amp;quot;raink                  : &amp;quot;.$raink.&amp;quot; &amp;quot;.$raink_base ;&lt;br /&gt;
          Log 3, &amp;quot;Solar_Correction_Rain  :  &amp;quot;.$Solar_Correction_Rain ;&lt;br /&gt;
          Log 3, &amp;quot;Solar_Temp             :  &amp;quot;.$Solar_Temp ;&lt;br /&gt;
          Log 3, &amp;quot;tempk                  : &amp;quot;.$tempk.&amp;quot; &amp;quot;.$tempk_base ;&lt;br /&gt;
          Log 3, &amp;quot;Solar_Correction_Temp  :  &amp;quot;.$Solar_Correction_Temp ;&lt;br /&gt;
          Log 3, $fc.&amp;quot;    &amp;quot;.$i.&amp;quot; &amp;quot;.$Solar_SolarRadiation.&amp;quot; &amp;quot;.$logentry ;&lt;br /&gt;
         } ;&lt;br /&gt;
      } ;&lt;br /&gt;
    return (0);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Solar_Plain ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub Solar_plain($$$) {&lt;br /&gt;
&lt;br /&gt;
        my $angle       = $_[0];&lt;br /&gt;
        my $orienta     = $_[1];&lt;br /&gt;
        my $time        = $_[2];&lt;br /&gt;
        my $azimuth     = fhem &amp;quot;get Astro text SunAz &amp;quot;.$time ;&lt;br /&gt;
&lt;br /&gt;
# angles in radiant&lt;br /&gt;
        my $rad         = 57.296;&lt;br /&gt;
        my $elevation   = fhem &amp;quot;get Astro text SunAlt &amp;quot;.$time ;&lt;br /&gt;
           $elevation   = $elevation / $rad;&lt;br /&gt;
        $angle          = $angle     / $rad;&lt;br /&gt;
        my $orientation = ($azimuth - 180 - $orienta) / $rad;&lt;br /&gt;
&lt;br /&gt;
#  avoid unrealistic values (normally formula should only be used within boundaries of orientation +/- 90 degrees)&lt;br /&gt;
        return (0.001) if ($elevation &amp;lt;= 0.25); &lt;br /&gt;
&lt;br /&gt;
        if(cos($orientation) &amp;lt; 0.05 &amp;amp;&amp;amp; cos($orientation) &amp;gt; -0.2) {$orientation =$orientation - 0.2};&lt;br /&gt;
&lt;br /&gt;
#    Log3 &amp;quot;&amp;quot;, 1, &amp;quot;Solar radiation, azimuth = $azimuth, orientation=$orientation, elevation=$elevation, angle=$angle&amp;quot;;&lt;br /&gt;
     my $factor = sin($angle) /&lt;br /&gt;
         (sin( $elevation) / &lt;br /&gt;
          cos( $elevation)) * &lt;br /&gt;
        cos($orientation) +&lt;br /&gt;
                cos($angle);&lt;br /&gt;
&lt;br /&gt;
# otherwise too big values (normally formula should only be used within boundaries of orientation +/- 90 degrees)&lt;br /&gt;
    if ($factor &amp;gt; - 0.05 &amp;amp;&amp;amp; $factor &amp;lt; 0.05) {$factor = 0.05};&lt;br /&gt;
&lt;br /&gt;
    return ($factor);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== wunderground ===&lt;br /&gt;
Diesen Dienst nutze ich nicht für die Prognose, jedoch kann man dort private Wetterstationen in seinem näheren Umfeld finden, die die Sonneneinstrahlung und den UV Index messen. Das ist dann als aktueller Wert in den Diagrammen zu sehen und lässt aktuelle Beschattung durch Wolken erkennen. Hier kann man dann auch mehrere Stationen definieren und eventuell mit einem Durchschnitt arbeiten, wenn nicht gerade der Nachbar eine Station hat.&lt;br /&gt;
Für diese Abfrage ist keine Registrierung notwendig und man muss auch nicht selber mir einer Station Daten liefern.&lt;br /&gt;
Aber bitte, die Abfrage nicht in einem zu kurzen Abstand, also mit hoher Frequenz stellen! Hier wird alle 15 Minuten (900 Sekunden) abgefragt.&lt;br /&gt;
=== RAW Definition Wetter_&amp;lt;Wohnort&amp;gt; ===&lt;br /&gt;
Ggf. muss UConv vorher noch aktiviert werden:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
define uconvInit notify global:INITIALIZED {use UConv}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod wetter_&amp;lt;Wohnort&amp;gt; HTTPMOD https://www.wunderground.com/dashboard/pws/&amp;lt;Wohnort_Station&amp;gt; 900&lt;br /&gt;
&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogExclude .*&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogInclude solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; alias wetter_&amp;lt;Wohnort&amp;gt;&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; enableControlSet 1&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; event-on-change-reading solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; group ASC Environment&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; icon weather_sunrise&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Name date&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Regex Summary.*&amp;gt;([[:alpha:]]{1,8} [\d]{1,2}, [\d]{4})&amp;lt;.*Temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Name dewpointTemperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;.*HUMIDITY&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Name dewpointTemperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;.*HUMIDITY&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Name humidity&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Regex HUMIDITY.*&amp;gt;([\d\.]+)&amp;lt;.*WIND&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Name precip1hrmetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Regex PRECIP RATE.*&amp;gt;([\d\.]+)&amp;lt;.*PRECIP TOTAL&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Name preciptodaymetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Regex PRECIP TOTAL.*&amp;gt;([\d\.]+)&amp;lt;.*tile-precipitation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Name pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07OExpr UConv::inhg2hpa($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Name pressure_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Name solarRadiation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Regex SOLAR RADIATION.*CURRENT.*weather__text&amp;quot;&amp;gt;([\d\.]+)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Name solarUV&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Regex CURRENT UV.*&amp;gt;([\d\.]+)&amp;lt;.*UV RISK&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Name temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Name temperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Name windChill&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Name windChill_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Name windDirection&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15OExpr UConv::compasspoint2compasspoint($val,&amp;quot;en&amp;quot;,1,&amp;quot;de&amp;quot;)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Name windDirection_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Name windSpeed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Name windSpeed_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Name windGust&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Name windGust_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; sortby 03&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; stateFormat T: temperature °C | F: humidity % | W: windSpeed km/h | D: pressure hPa | U: solarUV | R: solarRadiation W/m²&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; timeout 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Diagramme ==&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
[[Bild:Plenticore_Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_2 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_2 SVG LogDB:SVG_LogDB_Photovoltaik_2:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_2.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-03-16 10:23:52&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Hauptverbraucher&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB PV_Anlage_1:Total_DC_Power:::$val=abs($val)&lt;br /&gt;
#LogDB PV_Anlage_1:Total_PV_Power_reserve::&lt;br /&gt;
#LogDB StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:::$val=abs($val)&lt;br /&gt;
#LogDB shelly02:Power_0::&lt;br /&gt;
#LogDB shelly03:Power::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC&#039; ls l1 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_PV_reserve&#039; ls l2 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Heizung&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Pool&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Waschmaschine&#039; ls l3 lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== RAW Definition Leistungsbezug ===&lt;br /&gt;
[[Bild:Plenticore_Leistungsbezug.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_3 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_3 SVG LogDB:SVG_LogDB_Photovoltaik_3:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_3.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-07-22 13:51:57&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Leistungsbezug&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
set yrange [0:9500]&lt;br /&gt;
set y2range [0:9500]&lt;br /&gt;
&lt;br /&gt;
#LogDB PV_Anlage_1:Total_DC_Power:::$val=abs($val)&lt;br /&gt;
#LogDB PV_Anlage_1:Home_own_consumption_from_PV::&lt;br /&gt;
#LogDB PV_Anlage_1:Home_own_consumption_from_battery::&lt;br /&gt;
#LogDB PV_Anlage_1:Home_own_consumption_from_grid::&lt;br /&gt;
#LogDB PV_Anlage_1:Actual_battery_charge_usable_Power::&lt;br /&gt;
#LogDB PV_Anlage_1:Total_DC_Power_Max::&lt;br /&gt;
#LogDB PV_Anlage_1:Battery_temperature:::$val=$val*100&lt;br /&gt;
#LogDB Heizung:heatSourceIN:::$val=$val*100&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Power&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;own_PV&#039; ls l2fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_use&#039; ls l0fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Grid_use&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_usable&#039; ls l4 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Max&#039; ls l6 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_Temp_Trend&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Out_Temp_Trend&#039; ls l2 lw 2 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== RAW Definition PV_Bilanz ===&lt;br /&gt;
[[Bild:SVG LogDB PV Bilanz.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_PV_Bilanz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Bilanz SVG LogDB:SVG_LogDB_PV_Bilanz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz alias SVG_LogDB_PV_Bilanz&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz fixedrange year&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Bilanz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-02 09:55:06&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Bilanz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB Dum.Energy:max_month_PVMonth::&lt;br /&gt;
#LogDB Dum.Energy:diff_week_PVMonth::&lt;br /&gt;
#LogDB Dum.Energy:diff_week_PVTotalMonth::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;PV-Bezug-Monat&#039; ls l2fill lw 2 with points,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;PV-Bezug-Woche&#039; ls l2fill lw 1 with fsteps,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;PV-Total-Woche&#039; ls l1fill lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RAW Definition Forecast / Calculation ===&lt;br /&gt;
[[Bild:Plenticore_Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_4 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_4 SVG LogDB:SVG_LogDB_Photovoltaik_4:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_4.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-17 08:58:42&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Forecast / Calculation&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set yrange [0:10000]&lt;br /&gt;
set y2range [0:10000]&lt;br /&gt;
&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=($val&amp;gt;0?$val*50+7000:7000)&lt;br /&gt;
#LogDB wetter_wolfskehlen_II:solarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_SolarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=7000&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_Calculation_fc1::&lt;br /&gt;
#LogDB PV_Anlage_1:Power_DC_Sum::&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_Calculation::&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_East::&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_South::&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_West::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Sonnenhöhe&#039; ls l7 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiation&#039; ls l8 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiationPrognose&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;70%&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation_fc1&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Power_DC_Sum&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;East&#039; ls l2 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;South&#039; ls l3 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;West&#039; ls l4 lw 0.5 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe ===&lt;br /&gt;
==== RAW Definition LWP_LuftWärmePumpe (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LWP dummy&lt;br /&gt;
attr LWP DbLogExclude .*&lt;br /&gt;
attr LWP DbLogInclude state&lt;br /&gt;
attr LWP alias LWP_LuftWärmePumpe&lt;br /&gt;
attr LWP group PV Eigenverbrauch&lt;br /&gt;
attr LWP icon sani_earth_source_heat_pump&lt;br /&gt;
attr LWP readingList LWP_Button PowerLevelMinTime PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr LWP room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP setList LWP_Button:uzsuToggle,on,off PowerLevelMinTime:slider,60,30,300 PowerLimitOn:slider,1000,250,4000 PowerLimitOff:slider,1000,250,4000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,900,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr LWP sortby 05&lt;br /&gt;
attr LWP stateFormat state&lt;br /&gt;
attr LWP verbose 0&lt;br /&gt;
attr LWP webCmd LWP_Button&lt;br /&gt;
&lt;br /&gt;
setstate LWP off&lt;br /&gt;
setstate LWP 2020-08-05 17:38:03 LWP_Button off&lt;br /&gt;
setstate LWP 2020-03-02 11:56:45 PowerLevelMinTime 600&lt;br /&gt;
setstate LWP 2020-02-05 14:11:42 PowerLimitOff 2250&lt;br /&gt;
setstate LWP 2020-03-02 11:56:39 PowerLimitOn 3000&lt;br /&gt;
setstate LWP 2019-08-02 10:31:21 RunTimeMin 3600&lt;br /&gt;
setstate LWP 2020-02-05 14:13:01 RunTimePerDay 28800&lt;br /&gt;
setstate LWP 2019-12-29 10:47:55 SetCmdOff set shelly01 off 0&lt;br /&gt;
setstate LWP 2019-07-22 15:35:59 SetCmdOn set shelly01 on 0&lt;br /&gt;
setstate LWP 2019-11-09 12:13:04 TimeEnd 16:00&lt;br /&gt;
setstate LWP 2020-04-02 13:51:54 TimeStart 12:30&lt;br /&gt;
setstate LWP 2020-08-05 17:38:03 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LWP_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
    ([LWP_Counter:pulseTimePerDay] &amp;gt;= [LWP:RunTimePerDay] and\&lt;br /&gt;
     [LWP_Counter:pulseTimeIncrement] &amp;gt;= [LWP:RunTimeMin] and\&lt;br /&gt;
     [LWP:state] ne &amp;quot;off&amp;quot; and [LWP:LWP_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot; LWP_PV cmd_1 PV : LWP off&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 50.0&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
  ( ([PV_Anlage_1:Total_PV_Power_reserve]+[StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung]) &amp;lt; [LWP:PowerLimitOff] and\&lt;br /&gt;
     [LWP_Counter:pulseTimeIncrement] &amp;gt;= [LWP:RunTimeMin] and\&lt;br /&gt;
     [LWP:state] ne &amp;quot;off&amp;quot; and\&lt;br /&gt;
     [LWP:LWP_Button] ne &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot; LWP_PV cmd_2 PV : LWP off&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 50.0&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außerkraft,\&lt;br /&gt;
##   wenn wärend der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [LWP:PowerLimitOff] and\&lt;br /&gt;
     [LWP_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
     [LWP_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
     [LWP:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_3 PV : Stop wait timer LWP&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([Astro:ObsSeason] ne &amp;quot;Sommer&amp;quot; and [Astro:ObsSeason] ne &amp;quot;Frühling&amp;quot; and\&lt;br /&gt;
     [PV_Anlage_1:Total_PV_Power_reserve] &amp;gt;= [LWP:PowerLimitOn] and\&lt;br /&gt;
     [[LWP:TimeStart]-[LWP:TimeEnd]] and\&lt;br /&gt;
     [LWP:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
     [LWP_Counter:pulseTimePerDay] &amp;lt; [LWP:RunTimePerDay] and\&lt;br /&gt;
     [Heizung:hotWaterTemperature] &amp;lt; 60 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_4 : LWP on&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP on&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 60.0&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Signal für den PV-Modus der LWP einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([LWP:LWP_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_5 PV : LWP on for manuel PV-Modus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP on&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 60.0&amp;quot;)}\&lt;br /&gt;
     )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Signal für den PV-Modus der LWP abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([LWP:LWP_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
     [$SELF:cmd_nr] eq &amp;quot;5&amp;quot;  )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_6 PV : LWP off after manuel PV-Modus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 50.0&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Stop wait Timer für das Abschalten, wenn die LWP beim Starten noch anläuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
   ([StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;gt; 300 and\&lt;br /&gt;
    [Heizung:opStateHeatPump1] eq &amp;quot;Wärmepumpe kommt&amp;quot; and\&lt;br /&gt;
    [Heizung:opStateHeatPump3] eq &amp;quot;Pumpenvorlauf&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
     ({Log 3, &amp;quot;LWP_PV cmd_7 : Stop wait timer LWP&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 LWP Ende\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
   ([StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;lt; 300 and\&lt;br /&gt;
    [LWP_Counter:pulseTimeIncrement] &amp;gt;= [LWP:RunTimeMin] and\&lt;br /&gt;
    ([Heizung:opStateHeatPump1] ne &amp;quot;Wärmepumpe läuft&amp;quot; or [Heizung:opStateHeatPump3] eq &amp;quot;Luftabtauen&amp;quot; ) and\&lt;br /&gt;
    ([$SELF:cmd_nr] eq &amp;quot;4&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;10&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_8 : LWP run finished&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 50.0&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading LWP LWP_Button off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 LWP Zwangseinschalten: Sollte das Brauchwasser noch nicht aufgeheizt sein, wird um die Hysterese erhöht.\&lt;br /&gt;
##   Dies kann passieren, wenn am Tag vorher der PV-Modus lief und dann das Wasser noch knapp über dem Mindestwert ist.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
   ([Astro:ObsSeason] ne &amp;quot;Sommer&amp;quot; and [Astro:ObsSeason] ne &amp;quot;Frühling&amp;quot; and\&lt;br /&gt;
    [[LWP:TimeEnd]] and\&lt;br /&gt;
    [Heizung:hotWaterTemperature] &amp;lt; 47 and\&lt;br /&gt;
    ([LWP_Counter:pulseTimePerDay] &amp;lt; [Pool:RunTimePerDay] or\&lt;br /&gt;
     [LWP_Counter:countsPerDay] eq 0) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_9 : LWP on for water heating&amp;quot;}\&lt;br /&gt;
\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget &amp;quot;. (ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperature&amp;quot;,46)+4))}\&lt;br /&gt;
\&lt;br /&gt;
     {Log 3, &amp;quot;LWP_PV cmd_9 : LWP hotWaterTemperatureTarget &amp;quot;.ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperatureTarget&amp;quot;,0)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 10 Hohe Priorität im Winter fuer die LWP\&lt;br /&gt;
##    Einschalten, wenn der Pool läuft, der Speicher geladen ist und noch Überschuss da ist.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([Astro:ObsSeason] eq &amp;quot;Winter&amp;quot; and\&lt;br /&gt;
     [PV_Anlage_1:Total_PV_Power_reserve] &amp;gt;= 2000 and\&lt;br /&gt;
     [shelly02:power_0] &amp;gt; 800 and\&lt;br /&gt;
     [PV_Anlage_1:Act_state_of_charge] &amp;gt; 60 and\&lt;br /&gt;
     [Heizung:hotWaterTemperature] &amp;lt; 60 and \&lt;br /&gt;
     [$SELF:cmd_nr] ne &amp;quot;10&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_10 : LWP Priorität&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP_PV cmd_4&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
&lt;br /&gt;
attr LWP_PV DbLogExclude .*&lt;br /&gt;
attr LWP_PV DbLogInclude state,cmd.*,Device,LWP_Status,wait_timer&lt;br /&gt;
attr LWP_PV alias LWP_PV&lt;br /&gt;
attr LWP_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch aus|Stop wait timer|Eigenverbrauch ein|LWP ein für manuellen PV-Modus|LWP aus nach manuellem PV-Modus|Stop wait timer fuer aus|LWP aus nach PV-Modus|LWP Brauchwasser nachheizen|LWP Priorität&lt;br /&gt;
attr LWP_PV do always&lt;br /&gt;
attr LWP_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_PV icon sani_earth_source_heat_pump&lt;br /&gt;
attr LWP_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_PV sortby 01&lt;br /&gt;
attr LWP_PV stateFormat state : LWP_Status : Brauchwasser e_Heizung_hotWaterTemperature °C&lt;br /&gt;
attr LWP_PV userReadings LWP_Status { ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;state&amp;quot;,&amp;quot;&amp;quot;) }&lt;br /&gt;
attr LWP_PV verbose 5&lt;br /&gt;
attr LWP_PV wait 0:10:0:[LWP:PowerLevelMinTime]:0:0:900:0:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- RAW Definition LWP_Signale (Shelly Modul: shelly1pm)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly01 Shelly 192.168.178.55&lt;br /&gt;
attr shelly01 DbLogExclude .*&lt;br /&gt;
attr shelly01 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly01 alias LWP_Signale&lt;br /&gt;
attr shelly01 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly01 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly01 icon taster_ch_1&lt;br /&gt;
attr shelly01 mode relay&lt;br /&gt;
attr shelly01 model shelly1pm&lt;br /&gt;
attr shelly01 room Shelly,Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly01 sortby 02&lt;br /&gt;
attr shelly01 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;power&amp;quot;,0),\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly01 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly01 webCmd |&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod LWP_Counter HourCounter LWP:on.* LWP:off&lt;br /&gt;
attr LWP_Counter DbLogExclude .*&lt;br /&gt;
attr LWP_Counter alias LWP_Counter&lt;br /&gt;
attr LWP_Counter event-min-interval .*:600&lt;br /&gt;
attr LWP_Counter event-on-change-reading .*&lt;br /&gt;
attr LWP_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_Counter icon time_timer&lt;br /&gt;
attr LWP_Counter interval 5&lt;br /&gt;
attr LWP_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_Counter sortby 03&lt;br /&gt;
attr LWP_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition rg_LWP_Status (readingsGroup Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod rg_LWP_Status readingsGroup &amp;lt;Device&amp;gt;,&amp;lt;Information&amp;gt;,&amp;lt;Wert&amp;gt; LWP:&amp;lt;Status&amp;gt;,state LWP:&amp;lt;PowerLevelMinTime&amp;gt;,PowerLevelMinTime LWP:&amp;lt;PowerLimitOn&amp;gt;,PowerLimitOn LWP:&amp;lt;PowerLimitOff&amp;gt;,PowerLimitOff LWP:&amp;lt;TimeStart&amp;gt;,!TimeStart LWP:&amp;lt;TimeEnd&amp;gt;,!TimeEnd LWP:&amp;lt;RunTimeMin&amp;gt;,RunTimeMin LWP_Counter:&amp;lt;RunTimeMin&amp;gt;,pulseTimeIncrement LWP:&amp;lt;RunTimePerDay&amp;gt;,RunTimePerDay LWP_Counter:&amp;lt;RunTimePerDay&amp;gt;,pulseTimePerDay LWP_PV:&amp;lt;wait&amp;gt;,wait_timer LWP_PV:&amp;lt;TimeStart&amp;gt;,timer_01_c04 LWP_PV:&amp;lt;TimeEnd&amp;gt;,timer_02_c04&lt;br /&gt;
attr rg_LWP_Status DbLogExclude .*&lt;br /&gt;
attr rg_LWP_Status alias Status LuftWärmePumpe Eigenverbrauch&lt;br /&gt;
attr rg_LWP_Status commands {state  =&amp;gt; &#039;state:on,off&#039;,\&lt;br /&gt;
PowerLevelMinTime =&amp;gt; &#039;PowerLevelMinTime:selectnumbers,60,60,600,0,lin&#039;,\&lt;br /&gt;
PowerLimitOn =&amp;gt; &#039;PowerLimitOn:selectnumbers,1000,250,4000,0,lin&#039;,\&lt;br /&gt;
PowerLimitOff =&amp;gt; &#039;PowerLimitOff:selectnumbers,1000,250,4000,0,lin&#039;,\&lt;br /&gt;
RunTimeMin =&amp;gt; &#039;RunTimeMin:selectnumbers,300,300,14400,0,lin&#039;,\&lt;br /&gt;
RunTimePerDay =&amp;gt; &#039;RunTimePerDay:selectnumbers,300,300,28800,0,lin&#039;,\&lt;br /&gt;
TimeStart =&amp;gt; &#039;TimeStart:time&#039;,\&lt;br /&gt;
TimeEnd =&amp;gt; &#039;TimeEnd:time&#039;}&lt;br /&gt;
attr rg_LWP_Status group PV Status&lt;br /&gt;
attr rg_LWP_Status nameStyle style=&amp;quot;color:grey&amp;quot;&lt;br /&gt;
attr rg_LWP_Status room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr rg_LWP_Status sortby 01&lt;br /&gt;
attr rg_LWP_Status style style=&amp;quot;font-size:18px&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool===&lt;br /&gt;
==== RAW Definition Pool_Softube (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool dummy&lt;br /&gt;
attr Pool DbLogExclude .*&lt;br /&gt;
attr Pool DbLogInclude state&lt;br /&gt;
attr Pool alias Pool_Softube&lt;br /&gt;
attr Pool event-on-change-reading .*&lt;br /&gt;
attr Pool group PV Eigenverbrauch&lt;br /&gt;
attr Pool icon scene_swimming&lt;br /&gt;
attr Pool readingList Pool_Button PowerLevelMinTime PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay RunTimePerDaySummer RunTimePerDayWinter SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Pool room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool setList Pool_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,500,100,1500 PowerLimitOff:slider,0,100,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,900,300,64800 RunTimePerDaySummer:slider,900,300,7200 RunTimePerDayWinter:slider,3600,900,64800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Pool sortby 06&lt;br /&gt;
attr Pool stateFormat state&lt;br /&gt;
attr Pool verbose 0&lt;br /&gt;
attr Pool webCmd Pool_Button&lt;br /&gt;
&lt;br /&gt;
setstate Pool off&lt;br /&gt;
setstate Pool 2020-08-28 13:30:10 Pool_Button off&lt;br /&gt;
setstate Pool 2019-12-02 10:31:26 PowerLevelMinTime 600&lt;br /&gt;
setstate Pool 2019-11-13 10:58:18 PowerLimitOff 800&lt;br /&gt;
setstate Pool 2019-11-06 11:49:00 PowerLimitOn 1000&lt;br /&gt;
setstate Pool 2020-08-14 16:26:09 RunTimeMin 1800&lt;br /&gt;
setstate Pool 2020-08-28 06:15:00 RunTimePerDay 3600&lt;br /&gt;
setstate Pool 2020-08-16 13:17:45 RunTimePerDaySummer 3600&lt;br /&gt;
setstate Pool 2020-08-25 19:32:33 RunTimePerDayWinter 14400&lt;br /&gt;
setstate Pool 2019-08-01 14:18:08 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool 2019-08-02 09:33:06 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool 2019-10-31 21:53:28 TimeEnd 16:00&lt;br /&gt;
setstate Pool 2020-04-08 18:19:29 TimeStart 12:30&lt;br /&gt;
setstate Pool 2020-08-28 14:13:02 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
 ([Pool_Counter:pulseTimePerDay] &amp;gt;= [Pool:RunTimePerDay] and\&lt;br /&gt;
  [Pool_Counter:pulseTimeIncrement] &amp;gt;= [Pool:RunTimeMin] and\&lt;br /&gt;
  [Pool:state] eq &amp;quot;on&amp;quot; and [Pool:Pool_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_1 : Pool off&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist.\&lt;br /&gt;
##   Bei Pool Nutzung und Pflegeprogramm wird nicht abgeschaltet.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Pool:PowerLimitOff] and\&lt;br /&gt;
  [Pool_Counter:pulseTimeIncrement] &amp;gt;= [Pool:RunTimeMin] and\&lt;br /&gt;
  [Pool:state] eq &amp;quot;on&amp;quot; and \&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;10&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_2 : Pool off&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Pool Pool_Button off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
##   wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Pool:PowerLimitOff] and\&lt;br /&gt;
  [$SELF:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [$SELF:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Pool:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_3 : Stop wait timer Pool&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch einschalten: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist wird\&lt;br /&gt;
##    und die Laufzeit pro Tag noch nicht erreicht ist;; Bei über 7000 Watt Einspeisung sofort aktivieren\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_Anlage_1:Total_PV_Power_reserve] &amp;gt;= [Pool:PowerLimitOn] and\&lt;br /&gt;
   [[Pool:TimeStart]-[Pool:TimeEnd]] and\&lt;br /&gt;
   [Pool:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
   [Pool_Counter:pulseTimePerDay] &amp;lt; [Pool:RunTimePerDay]\&lt;br /&gt;
  ) or\&lt;br /&gt;
  [PV_Anlage_1:Total_active_power_(powermeter)] &amp;lt;= -7000\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_4 : Pool on&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool on&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose für die Benutzung des Pools einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Pool:Pool_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_5 : Pool on for usage&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool on&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Pools abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Pool:Pool_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_6 : Pool off after usage&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Stop wait Timer für das Abschalten, wenn die Pumpe beim Starten noch anläuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly02:power_0] &amp;gt; 10 and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;9&amp;quot;) and\&lt;br /&gt;
  [$SELF:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [$SELF:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Pool:state] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_7 : Stop wait timer Pool&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly02:power_0] &amp;lt; 10 and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;9&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_8 : Pool run finished&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Pool Pool_Button off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Pool:TimeEnd]] and\&lt;br /&gt;
  ([Pool_Counter:pulseTimePerDay] &amp;lt; [Pool:RunTimePerDay] or\&lt;br /&gt;
   [Pool_Counter:countsPerDay] eq 0)\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_9 : Pool on for maintanance&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool on&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 10 Pflege Zwangseinschaltung bei günstigem Strom nachts im Winter\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Astro:ObsSeason] eq &amp;quot;Winter&amp;quot; and\&lt;br /&gt;
  [Strom_Kosten:aWATTar_Trigger] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [22:00-05:00]\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_10 : Pool on for maintanance by aWATTar&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool on&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 11 Abschaltung bei teurem Strom\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Astro:ObsSeason] eq &amp;quot;Winter&amp;quot; and\&lt;br /&gt;
  [Strom_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;10&amp;quot;\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_11 : Pool off after maintanance by aWATTar&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 12 Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([06:15] and [Heizung:averageAmbientTemperature])\&lt;br /&gt;
\&lt;br /&gt;
    (\&lt;br /&gt;
     { if ( [Heizung:averageAmbientTemperature] &amp;gt;= 18 )\&lt;br /&gt;
         {fhem(&amp;quot;setreading Pool RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;RunTimePerDaySummer&amp;quot;,0) )}\&lt;br /&gt;
      else \&lt;br /&gt;
         {fhem(&amp;quot;setreading Pool RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;RunTimePerDayWinter&amp;quot;,0) )}\&lt;br /&gt;
     },\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV cmd_12 : Pool RunTimePerDay switched&amp;quot;}\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
attr Pool_PV DbLogExclude .*&lt;br /&gt;
attr Pool_PV DbLogInclude cmd.*,state,cmd.*,Device,Pool_Pumpe_Status,wait_timer&lt;br /&gt;
attr Pool_PV alias Pool_PV&lt;br /&gt;
attr Pool_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch aus|Stop wait timer|Eigenverbrauch freigegeben|Pool ein für Benutzung|Pool aus nach Benutzung|Stop wait timer für aus|Pool aus|Pflegemodus ohne PV|Strombörse ein|Strombörse aus|RunTimePerDay switched&lt;br /&gt;
attr Pool_PV disable 0&lt;br /&gt;
attr Pool_PV do always&lt;br /&gt;
attr Pool_PV event-on-change-reading .*&lt;br /&gt;
attr Pool_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV icon scene_swimming&lt;br /&gt;
attr Pool_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV sortby 11&lt;br /&gt;
attr Pool_PV stateFormat state : Pool_Pumpe_Status&lt;br /&gt;
attr Pool_PV userReadings Pool_Pumpe_Status { ReadingsVal(&amp;quot;shelly02&amp;quot;,&amp;quot;power_0&amp;quot;,0)&amp;gt;10 ? &amp;quot;Pool_Pumpe_laeuft&amp;quot; : &amp;quot;Pool_Pumpe_aus&amp;quot;}&lt;br /&gt;
attr Pool_PV verbose 0&lt;br /&gt;
attr Pool_PV wait 0:10:0:[Pool:PowerLevelMinTime]:0:0:0:300:0:300&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool_Signale&lt;br /&gt;
attr shelly02 comment relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 12&lt;br /&gt;
attr shelly02 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly02 userReadings WebLink:network { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_Counter HourCounter shelly02:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly02:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Pool_Counter DbLogExclude .*&lt;br /&gt;
attr Pool_Counter alias Pool_Counter&lt;br /&gt;
attr Pool_Counter comment On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Pool_Counter event-on-change-reading .*&lt;br /&gt;
attr Pool_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_Counter icon time_timer&lt;br /&gt;
attr Pool_Counter interval 5&lt;br /&gt;
attr Pool_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_Counter sortby 13&lt;br /&gt;
attr Pool_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition rg_Pool_Status (readingsGroup Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod rg_Pool_Status readingsGroup &amp;lt;Device&amp;gt;,&amp;lt;Information&amp;gt;,&amp;lt;Wert&amp;gt; Pool:&amp;lt;Status&amp;gt;,!state Pool:&amp;lt;PowerLevelMinTime&amp;gt;,!PowerLevelMinTime Pool:&amp;lt;PowerLimitOn&amp;gt;,!PowerLimitOn Pool:&amp;lt;PowerLimitOff&amp;gt;,!PowerLimitOff Pool:&amp;lt;TimeStart&amp;gt;,!TimeStart Pool:&amp;lt;TimeEnd&amp;gt;,!TimeEnd Pool:&amp;lt;RunTimeMin&amp;gt;,!RunTimeMin Pool_Counter:&amp;lt;RunTimeMin&amp;gt;,!pulseTimeIncrement Pool:&amp;lt;RunTimePerDay&amp;gt;,!RunTimePerDay Pool:&amp;lt;RunTimePerDaySummer&amp;gt;,!RunTimePerDaySummer Pool:&amp;lt;RunTimePerDayWinter&amp;gt;,!RunTimePerDayWinter Pool_Counter:&amp;lt;RunTimePerDay&amp;gt;,!pulseTimePerDay Pool_PV:&amp;lt;wait&amp;gt;,wait_timer Pool_PV:&amp;lt;TimeStart&amp;gt;,timer_01_c04 Pool_PV:&amp;lt;TimeEnd&amp;gt;,timer_02_c04&lt;br /&gt;
attr rg_Pool_Status DbLogExclude .*&lt;br /&gt;
attr rg_Pool_Status alias Status Softube Pool Eigenverbrauch&lt;br /&gt;
attr rg_Pool_Status commands {state  =&amp;gt; &#039;state:on,off&#039;,\&lt;br /&gt;
PowerLevelMinTime =&amp;gt; &#039;PowerLevelMinTime:selectnumbers,60,30,600,0,lin&#039;,\&lt;br /&gt;
PowerLimitOn =&amp;gt; &#039;PowerLimitOn:selectnumbers,500,250,1500,0,lin&#039;,\&lt;br /&gt;
PowerLimitOff =&amp;gt; &#039;PowerLimitOff:selectnumbers,0,100,1000,0,lin&#039;,\&lt;br /&gt;
RunTimeMin =&amp;gt; &#039;RunTimeMin:selectnumbers,300,300,14400,0,lin&#039;,\&lt;br /&gt;
RunTimePerDaySummer =&amp;gt; &#039;RunTimePerDaySummer:selectnumbers,300,300,3600,0,lin&#039;,\&lt;br /&gt;
RunTimePerDayWinter =&amp;gt; &#039;RunTimePerDayWinter:selectnumbers,3600,900,64800,0,lin&#039;,\&lt;br /&gt;
TimeStart =&amp;gt; &#039;TimeStart:time&#039;,\&lt;br /&gt;
TimeEnd =&amp;gt; &#039;TimeEnd:time&#039;}&lt;br /&gt;
attr rg_Pool_Status group PV Status&lt;br /&gt;
attr rg_Pool_Status nameStyle style=&amp;quot;color:grey&amp;quot;&lt;br /&gt;
attr rg_Pool_Status room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr rg_Pool_Status sortby 02&lt;br /&gt;
attr rg_Pool_Status style style=&amp;quot;font-size:18px&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine dummy&lt;br /&gt;
attr Waschmaschine DbLogExclude .*&lt;br /&gt;
attr Waschmaschine DbLogInclude state&lt;br /&gt;
attr Waschmaschine alias Waschmaschine&lt;br /&gt;
attr Waschmaschine group PV Eigenverbrauch&lt;br /&gt;
attr Waschmaschine icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine readingList Waschmaschine_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Waschmaschine room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine setList Waschmaschine_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Waschmaschine sortby 07&lt;br /&gt;
attr Waschmaschine stateFormat state&lt;br /&gt;
attr Waschmaschine verbose 0&lt;br /&gt;
attr Waschmaschine webCmd Waschmaschine_Button&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine off&lt;br /&gt;
setstate Waschmaschine 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine 2019-11-06 10:56:22 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine 2020-04-20 13:06:04 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine 2019-12-02 15:01:18 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine 2020-04-02 13:59:34 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine 2020-01-01 16:29:10 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine 2020-01-01 16:29:24 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine 2019-08-01 14:25:25 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Waschmaschine 2020-08-27 16:17:23 Waschmaschine_Button off&lt;br /&gt;
setstate Waschmaschine 2020-08-28 16:29:42 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [Waschmaschine:RunTimePerDay] and\&lt;br /&gt;
  [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [Waschmaschine:RunTimeMin] and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;on&amp;quot; and [Waschmaschine:Waschmaschine_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Waschprogramm bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
## ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Waschmaschine:PowerLimitOff] and\&lt;br /&gt;
##  [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [Waschmaschine:RunTimeMin] and\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Waschmaschine:PowerLimitOn] and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Waschmaschine:PowerLimitOff] and\&lt;br /&gt;
  [Waschmaschine_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Waschmaschine_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_3 : Waschmaschine stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;gt; [Waschmaschine:PowerLimitOn] and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Waschmaschine:TimeStart]-[Waschmaschine:TimeEnd]] and\&lt;br /&gt;
  [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [Waschmaschine:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_4 : Waschmaschine freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung der Waschmaschine einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Waschmaschine:Waschmaschine_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_5 : Waschmaschine manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose der Waschmaschine manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Waschmaschine:Waschmaschine_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_6 : Waschmaschine manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly03:power] &amp;gt; 0 and\&lt;br /&gt;
  [shelly03:power_Waschmaschine_avg] &amp;lt; 70 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_7 : Waschmaschine Programm gestarted&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Waschprogramm gestartet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose beim Waschprogramm Ende\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly03:power] == 0 and\&lt;br /&gt;
  [shelly03:power_Waschmaschine_avg] &amp;gt; 0 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_8 : Waschmaschine aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine Waschmaschine_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Waschprogramm beendet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn die Waschmaschine nicht gebraucht wurde\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Waschmaschine:PowerLimitOn] and\&lt;br /&gt;
  [[Waschmaschine:TimeEnd]-[Waschmaschine:TimeStart]] and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine Waschmaschine_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Waschmaschine_PV DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV DbLogInclude state,STATE,cmd.*,Device,Waschmaschine_Status,wait_timer&lt;br /&gt;
attr Waschmaschine_PV alias Waschmaschine_PV&lt;br /&gt;
attr Waschmaschine_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Waschmaschine manuell ein|Waschmaschine manuell aus|Waschmaschine laeuft|Waschmaschine aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Waschmaschine_PV do always&lt;br /&gt;
attr Waschmaschine_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV sortby 21&lt;br /&gt;
attr Waschmaschine_PV stateFormat state : Waschmaschine_Status&lt;br /&gt;
attr Waschmaschine_PV verbose 0&lt;br /&gt;
attr Waschmaschine_PV wait 0:0:0:[Waschmaschine:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.54&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine_Signale&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 22&lt;br /&gt;
attr shelly03 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly03 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) },\&lt;br /&gt;
power_Waschmaschine_avg:power.* { movingAverage($NAME,&amp;quot;power&amp;quot;,300) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 23&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition rg_Waschmaschine_Status (readingsGroup Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod rg_Waschmaschine_Status readingsGroup &amp;lt;Device&amp;gt;,&amp;lt;Information&amp;gt;,&amp;lt;Wert&amp;gt; Waschmaschine:&amp;lt;Status&amp;gt;,!state Waschmaschine:&amp;lt;PowerLevelMinTime&amp;gt;,!PowerLevelMinTime Waschmaschine:&amp;lt;PowerLimitOn&amp;gt;,!PowerLimitOn Waschmaschine:&amp;lt;PowerLimitOff&amp;gt;,!PowerLimitOff Waschmaschine:&amp;lt;TimeStart&amp;gt;,!TimeStart Waschmaschine:&amp;lt;TimeEnd&amp;gt;,!TimeEnd Waschmaschine:&amp;lt;RunTimeMin&amp;gt;,!RunTimeMin Waschmaschine_Counter:&amp;lt;RunTimeMin&amp;gt;,!pulseTimeIncrement Waschmaschine:&amp;lt;RunTimePerDay&amp;gt;,!RunTimePerDay Waschmaschine_Counter:&amp;lt;RunTimePerDay&amp;gt;,!pulseTimePerDay Waschmaschine_PV:&amp;lt;wait&amp;gt;,wait_timer Waschmaschine_PV:&amp;lt;TimeStart&amp;gt;,timer_01_c04 Waschmaschine_PV:&amp;lt;TimeEnd&amp;gt;,timer_02_c04&lt;br /&gt;
attr rg_Waschmaschine_Status DbLogExclude .*&lt;br /&gt;
attr rg_Waschmaschine_Status alias Status Waschmaschine Eigenverbrauch&lt;br /&gt;
attr rg_Waschmaschine_Status commands {state  =&amp;gt; &#039;state:on,off&#039;,\&lt;br /&gt;
PowerLevelMinTime =&amp;gt; &#039;PowerLevelMinTime:selectnumbers,30,30,300,0,lin&#039;,\&lt;br /&gt;
PowerLimitOn =&amp;gt; &#039;PowerLimitOn:selectnumbers,250,250,2000,0,lin&#039;,\&lt;br /&gt;
PowerLimitOff =&amp;gt; &#039;PowerLimitOff:selectnumbers,0,50,800,0,lin&#039;,\&lt;br /&gt;
RunTimeMin =&amp;gt; &#039;RunTimeMin:selectnumbers,300,300,7200,0,lin&#039;,\&lt;br /&gt;
RunTimePerDay =&amp;gt; &#039;RunTimePerDay:selectnumbers,7200,300,28800,0,lin&#039;,\&lt;br /&gt;
TimeStart =&amp;gt; &#039;TimeStart:time&#039;,\&lt;br /&gt;
TimeEnd =&amp;gt; &#039;TimeEnd:time&#039;}&lt;br /&gt;
attr rg_Waschmaschine_Status group PV Status&lt;br /&gt;
attr rg_Waschmaschine_Status nameStyle style=&amp;quot;color:grey&amp;quot;&lt;br /&gt;
attr rg_Waschmaschine_Status room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr rg_Waschmaschine_Status sortby 03&lt;br /&gt;
attr rg_Waschmaschine_Status style style=&amp;quot;font-size:18px&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Other Components]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33869</id>
		<title>Benutzer:Plin53177</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33869"/>
		<updated>2020-09-05T18:25:08Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Log */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FHEM Landschaft (2020)==&lt;br /&gt;
[[Datei:Plin53177 landscape.PNG|rahmenlos|1261x1261px]]&lt;br /&gt;
&lt;br /&gt;
==FHEM-Instanzen==&lt;br /&gt;
===Main===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Hausmitte&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 3B&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic)&lt;br /&gt;
SIGNALduino (433 MHz, OOK)&lt;br /&gt;
|für Homematic-Devices&lt;br /&gt;
&lt;br /&gt;
für diverse Funkthermometer&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Zentrale Steuerung&lt;br /&gt;
Funkbasierte Steuerung&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|Alarm, CUL, CUL_HM, CUL_TCM97001, CUL_TX, DOIF, Dashboard, ESPEasy, FHEM2FHEM, FHEMWEB, FLAMINGO, FLOORPLAN, FileLog, HMLAN, HMinfo, HTTPSRV, HUEBridge, HUEDevice, HourCounter, IT, LEDStripe, LightScene, MSGMail, OREGON, PRESENCE, RESIDENTS, RFHEM, ROLLO, ROOMMATE, SD_WS, SD_WS07, SIGNALduino, SVG, SYSMON, THRESHOLD, TelegramBot, Text2Speech, Weather, WifiLight, at, autocreate, autoload_undefined_devices, cmdalias, define, devStateIcon, dummy, eventTypes, laststate, notify, readingsGroup, siri, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Server===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|x86-Server mit OpenSUSE Leap 15.1&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic) mit hmland&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|IP-basierte Module/Dienste&lt;br /&gt;
CUL-Verlängerung für Aktoren im Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|CALVIEW, CUL_HM, Calendar, DOIF, Dashboard, ESPEasy, FB_CALLLIST, FB_CALLMONITOR, FHEM2FHEM, FHEMWEB, FRITZBOX, FileLog, HTTPMOD, HTTPSRV, IPCAM, MPD, RFHEM, SIP, SIRD, STV, TelegramBot, Text2Speech, WOL, allowed, at, autocreate, autoload_undefined_devices, dummy, eventTypes, notify, onCreateEvent, plex, readingsGroup, telnet, vitoconnect, weblink&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Sonstiges&lt;br /&gt;
|collectd für Fritz!Box 7490&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Wohnzimmer===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Erdgeschoss&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|SIGNALduino (868 MHz, GFSK)&lt;br /&gt;
Lautsprecher&lt;br /&gt;
|für die Rolläden&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Rolladensteuerung&lt;br /&gt;
Sound-Ausgabe&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, FHEMWEB, FileLog, MsgQueue, PRESENCE, RFHEM, ROLLO, SD_Keeloq, SIGNALduino, Text2Speech, autocreate, autoload_undefined_devices, dummy, eventTypes, msgConfig, notify, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Log===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|docker container auf Server&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|(docker container)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|keine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Sammelt per FHEM2FHEM alle Metriken für die Visualisierung in Grafana&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, DockerImageInfo, FHEM, FHEM2FHEM, FHEMWEB, InfluxDBLog, RFHEM, dummy, eventTypes, notify, telnet&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
Wenn es bei der Speicherung von Daten in der InfluxDB zu IP-technischen Verzögerungen kommt, kann die gesamte FHEM-Instanz blockiert werden. Durch die Auslagerung in eine separate Instanz wird dies vermieden.&lt;br /&gt;
&lt;br /&gt;
==Visualisierung==&lt;br /&gt;
===Prometheus===&lt;br /&gt;
für die Sammlung von collectd-Zeitreihen, node_exporter etc.&lt;br /&gt;
===InfluxDB===&lt;br /&gt;
für die Sammlung von FHEM-Zeitreihen&lt;br /&gt;
===Grafana===&lt;br /&gt;
für die übergreifende Visualisierung von Zeitreihen&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33868</id>
		<title>Benutzer:Plin53177</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33868"/>
		<updated>2020-09-05T18:23:57Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Visualisierung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FHEM Landschaft (2020)==&lt;br /&gt;
[[Datei:Plin53177 landscape.PNG|rahmenlos|1261x1261px]]&lt;br /&gt;
&lt;br /&gt;
==FHEM-Instanzen==&lt;br /&gt;
===Main===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Hausmitte&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 3B&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic)&lt;br /&gt;
SIGNALduino (433 MHz, OOK)&lt;br /&gt;
|für Homematic-Devices&lt;br /&gt;
&lt;br /&gt;
für diverse Funkthermometer&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Zentrale Steuerung&lt;br /&gt;
Funkbasierte Steuerung&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|Alarm, CUL, CUL_HM, CUL_TCM97001, CUL_TX, DOIF, Dashboard, ESPEasy, FHEM2FHEM, FHEMWEB, FLAMINGO, FLOORPLAN, FileLog, HMLAN, HMinfo, HTTPSRV, HUEBridge, HUEDevice, HourCounter, IT, LEDStripe, LightScene, MSGMail, OREGON, PRESENCE, RESIDENTS, RFHEM, ROLLO, ROOMMATE, SD_WS, SD_WS07, SIGNALduino, SVG, SYSMON, THRESHOLD, TelegramBot, Text2Speech, Weather, WifiLight, at, autocreate, autoload_undefined_devices, cmdalias, define, devStateIcon, dummy, eventTypes, laststate, notify, readingsGroup, siri, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Server===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|x86-Server mit OpenSUSE Leap 15.1&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic) mit hmland&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|IP-basierte Module/Dienste&lt;br /&gt;
CUL-Verlängerung für Aktoren im Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|CALVIEW, CUL_HM, Calendar, DOIF, Dashboard, ESPEasy, FB_CALLLIST, FB_CALLMONITOR, FHEM2FHEM, FHEMWEB, FRITZBOX, FileLog, HTTPMOD, HTTPSRV, IPCAM, MPD, RFHEM, SIP, SIRD, STV, TelegramBot, Text2Speech, WOL, allowed, at, autocreate, autoload_undefined_devices, dummy, eventTypes, notify, onCreateEvent, plex, readingsGroup, telnet, vitoconnect, weblink&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Sonstiges&lt;br /&gt;
|collectd für Fritz!Box 7490&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Wohnzimmer===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Erdgeschoss&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|SIGNALduino (868 MHz, GFSK)&lt;br /&gt;
Lautsprecher&lt;br /&gt;
|für die Rolläden&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Rolladensteuerung&lt;br /&gt;
Sound-Ausgabe&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, FHEMWEB, FileLog, MsgQueue, PRESENCE, RFHEM, ROLLO, SD_Keeloq, SIGNALduino, Text2Speech, autocreate, autoload_undefined_devices, dummy, eventTypes, msgConfig, notify, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Log===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|docker container auf Server&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|(docker container)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|keine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Sammelt per FHEM2FHEM alle Metriken für &lt;br /&gt;
die Visualisierung in Grafana&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, DockerImageInfo, FHEM, FHEM2FHEM, FHEMWEB, InfluxDBLog, RFHEM, dummy, eventTypes, notify, telnet&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
Wenn es bei der Speicherung von Daten in der InfluxDB zu IP-technischen Verzögerungen kommt, kann die gesamte FHEM-Instanz blockiert werden. Durch die Auslagerung in eine separate Instanz wird dies vermieden.&lt;br /&gt;
&lt;br /&gt;
==Visualisierung==&lt;br /&gt;
===Prometheus===&lt;br /&gt;
für die Sammlung von collectd-Zeitreihen, node_exporter etc.&lt;br /&gt;
===InfluxDB===&lt;br /&gt;
für die Sammlung von FHEM-Zeitreihen&lt;br /&gt;
===Grafana===&lt;br /&gt;
für die übergreifende Visualisierung von Zeitreihen&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33867</id>
		<title>Benutzer:Plin53177</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33867"/>
		<updated>2020-09-05T18:22:39Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Wohnzimmer */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FHEM Landschaft (2020)==&lt;br /&gt;
[[Datei:Plin53177 landscape.PNG|rahmenlos|1261x1261px]]&lt;br /&gt;
&lt;br /&gt;
==FHEM-Instanzen==&lt;br /&gt;
===Main===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Hausmitte&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 3B&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic)&lt;br /&gt;
SIGNALduino (433 MHz, OOK)&lt;br /&gt;
|für Homematic-Devices&lt;br /&gt;
&lt;br /&gt;
für diverse Funkthermometer&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Zentrale Steuerung&lt;br /&gt;
Funkbasierte Steuerung&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|Alarm, CUL, CUL_HM, CUL_TCM97001, CUL_TX, DOIF, Dashboard, ESPEasy, FHEM2FHEM, FHEMWEB, FLAMINGO, FLOORPLAN, FileLog, HMLAN, HMinfo, HTTPSRV, HUEBridge, HUEDevice, HourCounter, IT, LEDStripe, LightScene, MSGMail, OREGON, PRESENCE, RESIDENTS, RFHEM, ROLLO, ROOMMATE, SD_WS, SD_WS07, SIGNALduino, SVG, SYSMON, THRESHOLD, TelegramBot, Text2Speech, Weather, WifiLight, at, autocreate, autoload_undefined_devices, cmdalias, define, devStateIcon, dummy, eventTypes, laststate, notify, readingsGroup, siri, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Server===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|x86-Server mit OpenSUSE Leap 15.1&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic) mit hmland&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|IP-basierte Module/Dienste&lt;br /&gt;
CUL-Verlängerung für Aktoren im Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|CALVIEW, CUL_HM, Calendar, DOIF, Dashboard, ESPEasy, FB_CALLLIST, FB_CALLMONITOR, FHEM2FHEM, FHEMWEB, FRITZBOX, FileLog, HTTPMOD, HTTPSRV, IPCAM, MPD, RFHEM, SIP, SIRD, STV, TelegramBot, Text2Speech, WOL, allowed, at, autocreate, autoload_undefined_devices, dummy, eventTypes, notify, onCreateEvent, plex, readingsGroup, telnet, vitoconnect, weblink&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Sonstiges&lt;br /&gt;
|collectd für Fritz!Box 7490&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Wohnzimmer===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Erdgeschoss&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|SIGNALduino (868 MHz, GFSK)&lt;br /&gt;
Lautsprecher&lt;br /&gt;
|für die Rolläden&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Rolladensteuerung&lt;br /&gt;
Sound-Ausgabe&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, FHEMWEB, FileLog, MsgQueue, PRESENCE, RFHEM, ROLLO, SD_Keeloq, SIGNALduino, Text2Speech, autocreate, autoload_undefined_devices, dummy, eventTypes, msgConfig, notify, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Log===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|docker container auf Server&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|(docker container)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|keine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Sammelt per FHEM2FHEM alle Metriken für &lt;br /&gt;
die Visualisierung in Grafana&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, DockerImageInfo, FHEM, FHEM2FHEM, FHEMWEB, InfluxDBLog, RFHEM, dummy, eventTypes, notify, telnet&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
Wenn es bei der Speicherung von Daten in der InfluxDB zu IP-technischen Verzögerungen kommt, kann die gesamte FHEM-Instanz blockiert werden. Durch die Auslagerung in eine separate Instanz wird dies vermieden.&lt;br /&gt;
&lt;br /&gt;
===Visualisierung===&lt;br /&gt;
====Prometheus====&lt;br /&gt;
für die Sammlung von collectd-Zeitreihen, node_exporter etc.&lt;br /&gt;
====InfluxDB====&lt;br /&gt;
für die Sammlung von FHEM-Zeitreihen&lt;br /&gt;
====Grafana====&lt;br /&gt;
für die übergreifende Visualisierung von Zeitreihen&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33866</id>
		<title>Benutzer:Plin53177</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33866"/>
		<updated>2020-09-05T18:21:36Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Wohnzimmer */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FHEM Landschaft (2020)==&lt;br /&gt;
[[Datei:Plin53177 landscape.PNG|rahmenlos|1261x1261px]]&lt;br /&gt;
&lt;br /&gt;
==FHEM-Instanzen==&lt;br /&gt;
===Main===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Hausmitte&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 3B&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic)&lt;br /&gt;
SIGNALduino (433 MHz, OOK)&lt;br /&gt;
|für Homematic-Devices&lt;br /&gt;
&lt;br /&gt;
für diverse Funkthermometer&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Zentrale Steuerung&lt;br /&gt;
Funkbasierte Steuerung&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|Alarm, CUL, CUL_HM, CUL_TCM97001, CUL_TX, DOIF, Dashboard, ESPEasy, FHEM2FHEM, FHEMWEB, FLAMINGO, FLOORPLAN, FileLog, HMLAN, HMinfo, HTTPSRV, HUEBridge, HUEDevice, HourCounter, IT, LEDStripe, LightScene, MSGMail, OREGON, PRESENCE, RESIDENTS, RFHEM, ROLLO, ROOMMATE, SD_WS, SD_WS07, SIGNALduino, SVG, SYSMON, THRESHOLD, TelegramBot, Text2Speech, Weather, WifiLight, at, autocreate, autoload_undefined_devices, cmdalias, define, devStateIcon, dummy, eventTypes, laststate, notify, readingsGroup, siri, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Server===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|x86-Server mit OpenSUSE Leap 15.1&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic) mit hmland&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|IP-basierte Module/Dienste&lt;br /&gt;
CUL-Verlängerung für Aktoren im Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|CALVIEW, CUL_HM, Calendar, DOIF, Dashboard, ESPEasy, FB_CALLLIST, FB_CALLMONITOR, FHEM2FHEM, FHEMWEB, FRITZBOX, FileLog, HTTPMOD, HTTPSRV, IPCAM, MPD, RFHEM, SIP, SIRD, STV, TelegramBot, Text2Speech, WOL, allowed, at, autocreate, autoload_undefined_devices, dummy, eventTypes, notify, onCreateEvent, plex, readingsGroup, telnet, vitoconnect, weblink&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Sonstiges&lt;br /&gt;
|collectd für Fritz!Box 7490&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Wohnzimmer===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|rdgeschossE&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|SIGNALduino (868 MHz, GFSK)&lt;br /&gt;
Lautsprecher&lt;br /&gt;
|für die Rolläden&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Rolladensteuerung&lt;br /&gt;
Sound-Ausgabe&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, FHEMWEB, FileLog, MsgQueue, PRESENCE, RFHEM, ROLLO, SD_Keeloq, SIGNALduino, Text2Speech, autocreate, autoload_undefined_devices, dummy, eventTypes, msgConfig, notify, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Log===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|docker container auf Server&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|(docker container)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|keine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Sammelt per FHEM2FHEM alle Metriken für &lt;br /&gt;
die Visualisierung in Grafana&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, DockerImageInfo, FHEM, FHEM2FHEM, FHEMWEB, InfluxDBLog, RFHEM, dummy, eventTypes, notify, telnet&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
Wenn es bei der Speicherung von Daten in der InfluxDB zu IP-technischen Verzögerungen kommt, kann die gesamte FHEM-Instanz blockiert werden. Durch die Auslagerung in eine separate Instanz wird dies vermieden.&lt;br /&gt;
&lt;br /&gt;
===Visualisierung===&lt;br /&gt;
====Prometheus====&lt;br /&gt;
für die Sammlung von collectd-Zeitreihen, node_exporter etc.&lt;br /&gt;
====InfluxDB====&lt;br /&gt;
für die Sammlung von FHEM-Zeitreihen&lt;br /&gt;
====Grafana====&lt;br /&gt;
für die übergreifende Visualisierung von Zeitreihen&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33865</id>
		<title>Benutzer:Plin53177</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33865"/>
		<updated>2020-09-05T13:09:27Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Log */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FHEM Landschaft (2020)==&lt;br /&gt;
[[Datei:Plin53177 landscape.PNG|rahmenlos|1261x1261px]]&lt;br /&gt;
&lt;br /&gt;
==FHEM-Instanzen==&lt;br /&gt;
===Main===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Hausmitte&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 3B&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic)&lt;br /&gt;
SIGNALduino (433 MHz, OOK)&lt;br /&gt;
|für Homematic-Devices&lt;br /&gt;
&lt;br /&gt;
für diverse Funkthermometer&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Zentrale Steuerung&lt;br /&gt;
Funkbasierte Steuerung&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|Alarm, CUL, CUL_HM, CUL_TCM97001, CUL_TX, DOIF, Dashboard, ESPEasy, FHEM2FHEM, FHEMWEB, FLAMINGO, FLOORPLAN, FileLog, HMLAN, HMinfo, HTTPSRV, HUEBridge, HUEDevice, HourCounter, IT, LEDStripe, LightScene, MSGMail, OREGON, PRESENCE, RESIDENTS, RFHEM, ROLLO, ROOMMATE, SD_WS, SD_WS07, SIGNALduino, SVG, SYSMON, THRESHOLD, TelegramBot, Text2Speech, Weather, WifiLight, at, autocreate, autoload_undefined_devices, cmdalias, define, devStateIcon, dummy, eventTypes, laststate, notify, readingsGroup, siri, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Server===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|x86-Server mit OpenSUSE Leap 15.1&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic) mit hmland&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|IP-basierte Module/Dienste&lt;br /&gt;
CUL-Verlängerung für Aktoren im Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|CALVIEW, CUL_HM, Calendar, DOIF, Dashboard, ESPEasy, FB_CALLLIST, FB_CALLMONITOR, FHEM2FHEM, FHEMWEB, FRITZBOX, FileLog, HTTPMOD, HTTPSRV, IPCAM, MPD, RFHEM, SIP, SIRD, STV, TelegramBot, Text2Speech, WOL, allowed, at, autocreate, autoload_undefined_devices, dummy, eventTypes, notify, onCreateEvent, plex, readingsGroup, telnet, vitoconnect, weblink&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Sonstiges&lt;br /&gt;
|collectd für Fritz!Box 7490&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Wohnzimmer===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|rdgeschossE&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|SIGNALduino (868 MHz, GFSK)&lt;br /&gt;
Lautsprecher&lt;br /&gt;
|für die Rolläden&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Rolladensteuerung&lt;br /&gt;
Sound-Ausgabe&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, FHEMWEB, FileLog, MsqQueue, PRESENCE, RFHEM, ROLLO, SD_Keeloq, SIGNALduino, Text2Speech, autocreate, autoload_undefined_devices, dummy, eventTypes, msgConfig, notify, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Log===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|docker container auf Server&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|(docker container)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|keine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Sammelt per FHEM2FHEM alle Metriken für &lt;br /&gt;
die Visualisierung in Grafana&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, DockerImageInfo, FHEM, FHEM2FHEM, FHEMWEB, InfluxDBLog, RFHEM, dummy, eventTypes, notify, telnet&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
Wenn es bei der Speicherung von Daten in der InfluxDB zu IP-technischen Verzögerungen kommt, kann die gesamte FHEM-Instanz blockiert werden. Durch die Auslagerung in eine separate Instanz wird dies vermieden.&lt;br /&gt;
&lt;br /&gt;
===Visualisierung===&lt;br /&gt;
====Prometheus====&lt;br /&gt;
für die Sammlung von collectd-Zeitreihen, node_exporter etc.&lt;br /&gt;
====InfluxDB====&lt;br /&gt;
für die Sammlung von FHEM-Zeitreihen&lt;br /&gt;
====Grafana====&lt;br /&gt;
für die übergreifende Visualisierung von Zeitreihen&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33864</id>
		<title>Benutzer:Plin53177</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33864"/>
		<updated>2020-09-05T13:07:17Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Visualisierung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FHEM Landschaft (2020)==&lt;br /&gt;
[[Datei:Plin53177 landscape.PNG|rahmenlos|1261x1261px]]&lt;br /&gt;
&lt;br /&gt;
==FHEM-Instanzen==&lt;br /&gt;
===Main===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Hausmitte&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 3B&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic)&lt;br /&gt;
SIGNALduino (433 MHz, OOK)&lt;br /&gt;
|für Homematic-Devices&lt;br /&gt;
&lt;br /&gt;
für diverse Funkthermometer&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Zentrale Steuerung&lt;br /&gt;
Funkbasierte Steuerung&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|Alarm, CUL, CUL_HM, CUL_TCM97001, CUL_TX, DOIF, Dashboard, ESPEasy, FHEM2FHEM, FHEMWEB, FLAMINGO, FLOORPLAN, FileLog, HMLAN, HMinfo, HTTPSRV, HUEBridge, HUEDevice, HourCounter, IT, LEDStripe, LightScene, MSGMail, OREGON, PRESENCE, RESIDENTS, RFHEM, ROLLO, ROOMMATE, SD_WS, SD_WS07, SIGNALduino, SVG, SYSMON, THRESHOLD, TelegramBot, Text2Speech, Weather, WifiLight, at, autocreate, autoload_undefined_devices, cmdalias, define, devStateIcon, dummy, eventTypes, laststate, notify, readingsGroup, siri, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Server===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|x86-Server mit OpenSUSE Leap 15.1&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic) mit hmland&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|IP-basierte Module/Dienste&lt;br /&gt;
CUL-Verlängerung für Aktoren im Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|CALVIEW, CUL_HM, Calendar, DOIF, Dashboard, ESPEasy, FB_CALLLIST, FB_CALLMONITOR, FHEM2FHEM, FHEMWEB, FRITZBOX, FileLog, HTTPMOD, HTTPSRV, IPCAM, MPD, RFHEM, SIP, SIRD, STV, TelegramBot, Text2Speech, WOL, allowed, at, autocreate, autoload_undefined_devices, dummy, eventTypes, notify, onCreateEvent, plex, readingsGroup, telnet, vitoconnect, weblink&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Sonstiges&lt;br /&gt;
|collectd für Fritz!Box 7490&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Wohnzimmer===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|rdgeschossE&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|SIGNALduino (868 MHz, GFSK)&lt;br /&gt;
Lautsprecher&lt;br /&gt;
|für die Rolläden&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Rolladensteuerung&lt;br /&gt;
Sound-Ausgabe&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, FHEMWEB, FileLog, MsqQueue, PRESENCE, RFHEM, ROLLO, SD_Keeloq, SIGNALduino, Text2Speech, autocreate, autoload_undefined_devices, dummy, eventTypes, msgConfig, notify, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Log===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|docker container auf Server&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|(docker container)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|keine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Sammelt per FHEM2FHEM alle Metriken für &lt;br /&gt;
die Visualisierung in Grafana&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, DockerImageInfo, FHEM, FHEM2FHEM, FHEMWEB, InfluxDBLog, RFHEM, dummy, eventTypes, notify, telnet&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Visualisierung===&lt;br /&gt;
====Prometheus====&lt;br /&gt;
für die Sammlung von collectd-Zeitreihen, node_exporter etc.&lt;br /&gt;
====InfluxDB====&lt;br /&gt;
für die Sammlung von FHEM-Zeitreihen&lt;br /&gt;
====Grafana====&lt;br /&gt;
für die übergreifende Visualisierung von Zeitreihen&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33863</id>
		<title>Benutzer:Plin53177</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33863"/>
		<updated>2020-09-05T13:04:45Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FHEM Landschaft (2020)==&lt;br /&gt;
[[Datei:Plin53177 landscape.PNG|rahmenlos|1261x1261px]]&lt;br /&gt;
&lt;br /&gt;
==FHEM-Instanzen==&lt;br /&gt;
===Main===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Hausmitte&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 3B&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic)&lt;br /&gt;
SIGNALduino (433 MHz, OOK)&lt;br /&gt;
|für Homematic-Devices&lt;br /&gt;
&lt;br /&gt;
für diverse Funkthermometer&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Zentrale Steuerung&lt;br /&gt;
Funkbasierte Steuerung&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|Alarm, CUL, CUL_HM, CUL_TCM97001, CUL_TX, DOIF, Dashboard, ESPEasy, FHEM2FHEM, FHEMWEB, FLAMINGO, FLOORPLAN, FileLog, HMLAN, HMinfo, HTTPSRV, HUEBridge, HUEDevice, HourCounter, IT, LEDStripe, LightScene, MSGMail, OREGON, PRESENCE, RESIDENTS, RFHEM, ROLLO, ROOMMATE, SD_WS, SD_WS07, SIGNALduino, SVG, SYSMON, THRESHOLD, TelegramBot, Text2Speech, Weather, WifiLight, at, autocreate, autoload_undefined_devices, cmdalias, define, devStateIcon, dummy, eventTypes, laststate, notify, readingsGroup, siri, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Server===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|x86-Server mit OpenSUSE Leap 15.1&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic) mit hmland&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|IP-basierte Module/Dienste&lt;br /&gt;
CUL-Verlängerung für Aktoren im Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|CALVIEW, CUL_HM, Calendar, DOIF, Dashboard, ESPEasy, FB_CALLLIST, FB_CALLMONITOR, FHEM2FHEM, FHEMWEB, FRITZBOX, FileLog, HTTPMOD, HTTPSRV, IPCAM, MPD, RFHEM, SIP, SIRD, STV, TelegramBot, Text2Speech, WOL, allowed, at, autocreate, autoload_undefined_devices, dummy, eventTypes, notify, onCreateEvent, plex, readingsGroup, telnet, vitoconnect, weblink&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Sonstiges&lt;br /&gt;
|collectd für Fritz!Box 7490&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Wohnzimmer===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|rdgeschossE&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|SIGNALduino (868 MHz, GFSK)&lt;br /&gt;
Lautsprecher&lt;br /&gt;
|für die Rolläden&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Rolladensteuerung&lt;br /&gt;
Sound-Ausgabe&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, FHEMWEB, FileLog, MsqQueue, PRESENCE, RFHEM, ROLLO, SD_Keeloq, SIGNALduino, Text2Speech, autocreate, autoload_undefined_devices, dummy, eventTypes, msgConfig, notify, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Log===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|docker container auf Server&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|(docker container)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|keine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Sammelt per FHEM2FHEM alle Metriken für &lt;br /&gt;
die Visualisierung in Grafana&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, DockerImageInfo, FHEM, FHEM2FHEM, FHEMWEB, InfluxDBLog, RFHEM, dummy, eventTypes, notify, telnet&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Visualisierung===&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33862</id>
		<title>Benutzer:Plin53177</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33862"/>
		<updated>2020-09-05T12:45:07Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FHEM Landschaft (2020)==&lt;br /&gt;
[[Datei:Plin53177 landscape.PNG|rahmenlos|1261x1261px]]&lt;br /&gt;
&lt;br /&gt;
==FHEM-Instanzen==&lt;br /&gt;
===Main===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Hausmitte&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 3B&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic)&lt;br /&gt;
SIGNALduino (433 MHz, OOK)&lt;br /&gt;
|für Homematic-Devices&lt;br /&gt;
&lt;br /&gt;
für diverse Funkthermometer&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Zentrale Steuerung&lt;br /&gt;
Funkbasierte Steuerung&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|Alarm, CUL, CUL_HM, CUL_TCM97001, CUL_TX, DOIF, Dashboard, ESPEasy, FHEM2FHEM, FHEMWEB, FLAMINGO, FLOORPLAN, FileLog, HMLAN, HMinfo, HTTPSRV, HUEBridge, HUEDevice, HourCounter, IT, LEDStripe, LightScene, MSGMail, OREGON, PRESENCE, RESIDENTS, RFHEM, ROLLO, ROOMMATE, SD_WS, SD_WS07, SIGNALduino, SVG, SYSMON, THRESHOLD, TelegramBot, Text2Speech, Weather, WifiLight, at, autocreate, autoload_undefined_devices, cmdalias, define, devStateIcon, dummy, eventTypes, laststate, notify, readingsGroup, siri, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Server===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|x86-Server mit OpenSUSE Leap 15.1&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic) mit hmland&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|IP-basierte Module/Dienste&lt;br /&gt;
CUL-Verlängerung für Aktoren im Keller&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|CALVIEW, CUL_HM, Calendar, DOIF, Dashboard, ESPEasy, FB_CALLLIST, FB_CALLMONITOR, FHEM2FHEM, FHEMWEB, FRITZBOX, FileLog, HTTPMOD, HTTPSRV, IPCAM, MPD, RFHEM, SIP, SIRD, STV, TelegramBot, Text2Speech, WOL, allowed, at, autocreate, autoload_undefined_devices, dummy, eventTypes, notify, onCreateEvent, plex, readingsGroup, telnet, vitoconnect, weblink&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Wohnzimmer===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|rdgeschossE&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|SIGNALduino (868 MHz, GFSK)&lt;br /&gt;
|für die Rolläden&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Rolladensteuerung&lt;br /&gt;
Sound-Ausgabe&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, FHEMWEB, FileLog, MsqQueue, PRESENCE, RFHEM, ROLLO, SD_Keeloq, SIGNALduino, Text2Speech, autocreate, autoload_undefined_devices, dummy, eventTypes, msgConfig, notify, structure, telnet, weblink &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Log===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|docker container auf Server&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|(docker container)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|keine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Sammelt per FHEM2FHEM alle Metriken für &lt;br /&gt;
die Visualisierung in Grafana&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|DOIF, DockerImageInfo, FHEM, FHEM2FHEM, FHEMWEB, InfluxDBLog, RFHEM, dummy, eventTypes, notify, telnet&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Visualisierung===&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33860</id>
		<title>Benutzer:Plin53177</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33860"/>
		<updated>2020-09-05T12:24:18Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Main */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FHEM Landschaft (2020)==&lt;br /&gt;
[[Datei:Plin53177 landscape.PNG|rahmenlos|1261x1261px]]&lt;br /&gt;
&lt;br /&gt;
==FHEM-Instanzen==&lt;br /&gt;
===Main===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Hausmitte&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 3B&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic)&lt;br /&gt;
SIGNALduino (433 MHz, OOK)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Zentrale Steuerung&lt;br /&gt;
Funkbasierte Steuerung&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Server===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Hausmitte&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 3B&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic)&lt;br /&gt;
SIGNALduino (433 MHz, OOK)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Zentrale Steuerung&lt;br /&gt;
Funkbasierte Steuerung&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Wohnzimmer===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Hausmitte&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 3B&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic)&lt;br /&gt;
SIGNALduino (433 MHz, OOK)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Zentrale Steuerung&lt;br /&gt;
Funkbasierte Steuerung&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Log===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!Info&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Hausmitte&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 3B&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic)&lt;br /&gt;
SIGNALduino (433 MHz, OOK)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Zentrale Steuerung&lt;br /&gt;
Funkbasierte Steuerung&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
===Visualisierung===&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33859</id>
		<title>Benutzer:Plin53177</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33859"/>
		<updated>2020-09-05T08:38:09Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FHEM Landschaft (2020)==&lt;br /&gt;
[[Datei:Plin53177 landscape.PNG|rahmenlos|1261x1261px]]&lt;br /&gt;
&lt;br /&gt;
==FHEM-Instanzen==&lt;br /&gt;
===Main===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Aspekt&lt;br /&gt;
!.&lt;br /&gt;
!Bemerkung&lt;br /&gt;
|-&lt;br /&gt;
|Position&lt;br /&gt;
|Hausmitte&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Hardware&lt;br /&gt;
|Raspberry Pi 3B&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Peripherie&lt;br /&gt;
|CUL (Homematic)&lt;br /&gt;
SIGNALduino (433 MHz, OOK)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Schwerpunkt&lt;br /&gt;
|Zentrale Steuerung&lt;br /&gt;
Funkbasierte Steuerung&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Module&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Server===&lt;br /&gt;
&lt;br /&gt;
===Wohnzimmer===&lt;br /&gt;
&lt;br /&gt;
===Log===&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Datei:Plin53177_landscape.PNG&amp;diff=33858</id>
		<title>Datei:Plin53177 landscape.PNG</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Datei:Plin53177_landscape.PNG&amp;diff=33858"/>
		<updated>2020-09-05T08:30:46Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: pli53177 FHEM Landscpae&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Beschreibung ==&lt;br /&gt;
pli53177 FHEM Landscpae&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33857</id>
		<title>Benutzer:Plin53177</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Benutzer:Plin53177&amp;diff=33857"/>
		<updated>2020-09-05T08:29:18Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: Die Seite wurde neu angelegt: „==FHEM Landschaft (2020)==  xxx  ==FHEM-Instanzen== ===Main===  ===Server===  ===Wohnzimmer===  ===Log===“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FHEM Landschaft (2020)==&lt;br /&gt;
&lt;br /&gt;
xxx&lt;br /&gt;
&lt;br /&gt;
==FHEM-Instanzen==&lt;br /&gt;
===Main===&lt;br /&gt;
&lt;br /&gt;
===Server===&lt;br /&gt;
&lt;br /&gt;
===Wohnzimmer===&lt;br /&gt;
&lt;br /&gt;
===Log===&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Solar-/PV-%C3%9Cbersicht&amp;diff=33833</id>
		<title>Solar-/PV-Übersicht</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Solar-/PV-%C3%9Cbersicht&amp;diff=33833"/>
		<updated>2020-09-02T18:27:11Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Wechselrichter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;float:right;margin-left:10px&amp;quot;&amp;gt;__TOC__&amp;lt;/div&amp;gt;&lt;br /&gt;
Die Seite [[Solar-/PV-Übersicht]] soll einen schnellen Einstieg in die für Solar-/Photovoltaik-Betreiber relevanten Seiten und Threads ermöglichen. Bitte bei Bedarf selbständig ergänzen.&lt;br /&gt;
&lt;br /&gt;
==Forum==&lt;br /&gt;
Der Forenbereich {{Link2Forum|Area=Solaranlagen}} enthält Themen rund um Solaranlagen zur Wärme- oder Stromgewinnung&lt;br /&gt;
&lt;br /&gt;
== Allgemein ==&lt;br /&gt;
* [[Fotovoltaikanlage]]&lt;br /&gt;
* Viele Seiten der Kategorie [[:Kategorie:Energieerzeugungsmessung|Energieerzeugungsmessung]]&lt;br /&gt;
&lt;br /&gt;
==Wechselrichter==&lt;br /&gt;
===Kostal===&lt;br /&gt;
* [[KostalPiko]]&lt;br /&gt;
* [[Kostal Plenticore 10 Plus]]&lt;br /&gt;
&lt;br /&gt;
===SMA===&lt;br /&gt;
* [[SMAWechselrichter]]&lt;br /&gt;
&lt;br /&gt;
===Solar Edge===&lt;br /&gt;
* [[SolarEdge SE10k]]&lt;br /&gt;
&lt;br /&gt;
===Sunways===&lt;br /&gt;
* [[NT5000]]&lt;br /&gt;
&lt;br /&gt;
==Speicher==&lt;br /&gt;
* [[Sonnenspeicher]]&lt;br /&gt;
&lt;br /&gt;
==Monitoring/Auswertung==&lt;br /&gt;
* [[Enecsys Monitoring System]]&lt;br /&gt;
* [[SunnyHomeManager]]&lt;br /&gt;
* [[Datenbankgestützte Erstellung der Energiebilanz einer SMA PV-Anlage mit Überschusseinspeisung]]&lt;br /&gt;
* [[SolarLog]]&lt;br /&gt;
&lt;br /&gt;
==Angrenzende Themen==&lt;br /&gt;
Verwandte Themen, &amp;quot;gern verwendete&amp;quot; oder erforderliche Module, etc.:&lt;br /&gt;
* [[ModbusAttr]]&lt;br /&gt;
* [[SMLUSB]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=33829</id>
		<title>Kostal Plenticore 10 Plus</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kostal_Plenticore_10_Plus&amp;diff=33829"/>
		<updated>2020-09-02T06:46:46Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: Kategorie Energieerzeugungsmessung ergänzt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Infobox Hardware&lt;br /&gt;
|Bild=Kostal_Plenticore_10_Plus.jpg&lt;br /&gt;
|Bildbeschreibung=Kostal Plenticore 10 Plus&lt;br /&gt;
|HWProtocol=IP und RS485&lt;br /&gt;
|HWType=Hybrid Wechselrichter&lt;br /&gt;
|HWCategory=Wechselrichter&lt;br /&gt;
|HWComm=n/a&lt;br /&gt;
|HWChannels=n/a&lt;br /&gt;
|HWVoltage=400&amp;amp;nbsp;V&lt;br /&gt;
|HWPowerConsumption=&lt;br /&gt;
|HWPoweredBy=3P AC&lt;br /&gt;
|HWSize=56,3x40,5x23,3 cm (BxHxT)&lt;br /&gt;
|HWDeviceFHEM=[[HTTPMOD]], [[Modbus]], [[Python3]]&lt;br /&gt;
&amp;lt;!-- |ModOwner=  --&amp;gt;&lt;br /&gt;
|HWManufacturer=KOSTAL Solar Electric GmbH&lt;br /&gt;
}}&lt;br /&gt;
[[Bild:Plenticore FHEM 1.png|mini|900px|rechts|Die Diagramme im Überblick]]&lt;br /&gt;
[[Bild:Plenticore FHEM 2.png|mini|900px|rechts|Geräte Überblick mit manueller Schaltmöglichkeit]]&lt;br /&gt;
[[Bild:Plenticore FHEM 3.png|mini|900px|rechts|Steuerungsgeräte für die Schaltlogik]]&lt;br /&gt;
[[Bild:Plenticore FHEM 4.png|mini|900px|rechts|ReadingsGroup für die schnelle Parametereinstellung]]&lt;br /&gt;
&lt;br /&gt;
Ein Hinweis allgemeiner Art: Die hier abgebildeten Code Stücke sind nicht ausschließlich durch mich entstanden. Ich bedanke mich für die Unterstützung und Bereitstellung vieler Einzelkomponenten durch Dritte. Der Einsatz ist auf eigene Gefahr und für etwaige Schäden wird keinerlei Haftung übernommen. Bitte beachtet bei der Hardware die Gewährleistungsbestimmungen und Vorgaben der Hersteller.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der [[Kostal Plenticore 10 Plus]] [https://www.kostal-solar-electric.com/de-de/produkte/hybrid-wechselrichter/ Hersteller Link] ist ein Hybrid Wechselrichter mit IP-Konnektivität. &lt;br /&gt;
&lt;br /&gt;
Er verfügt über einen LAN-Anschluss und ist auf die Steuerung via WebGUI des Herstellers ausgelegt. Weiterhin kann eine Abfrage mit Modbus/TCP oder auch über eine undokumentierte API erfolgen. Für die API bietet der Hersteller keinerlei Support!&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen Energietechnik ==&lt;br /&gt;
&lt;br /&gt;
Der Wechselrichter, der Speicher und der KSEM wurden durch einen Fachbetrieb installiert und konfiguriert. Die gesamte Anlage läuft fehlerfrei und wurde durch den Fachbetrieb abgenommen, sowie beim  Netzbetreiber angemeldet.&lt;br /&gt;
&lt;br /&gt;
== Geräte-Registrierung ==&lt;br /&gt;
&lt;br /&gt;
Hierfür ist die Dokumentation des Herstellers heranzuziehen. Für eine Verlängerung der Gewährleistungszeit kann man den Plenticore im Herstellerportal registrieren. Dies ist jedoch für die Anbindung an FHEM nicht notwendig.&lt;br /&gt;
&lt;br /&gt;
== Hersteller Dokumentation ==&lt;br /&gt;
&lt;br /&gt;
Für Links auf dieser Wiki Seite wird keine Haftung übernommen. Die Inhalte unterliegen der Verantwortung der Firma Kostal.&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/smart-warranty/ Plenticore Plus - Verlängerung der Gewährleistungszeit]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2018/06/15/11/40/plenticore-plus_ba_de.pdf/ Plenticore Plus - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2018/04/12/08/26/plenticore-plus_kba.pdf/ Plenticore Plus - Kurzanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2018/04/12/08/26/db_plenticore-plus_de.pdf/ Plenticore Plus - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2019/03/12/07/13/kostal_update_plenticore_piko_iq_011504581.swu/ Plenticore Plus - Software Update UI: 01.15.04581 FW: 01.43]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2018/08/30/08/53/ba_kostal_interface_modbus-tcp_sunspec.pdf/ Plenticore - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2019/03/06/13/17/ksem-ba_de.pdf/ KSEM - Betriebsanleitung]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2019/03/06/13/17/ksem-db_de.pdf/ KSEM - Datenblatt]&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2020/06/09/11/49/kostal_update_ksem_1_2_1.zip/ KSEM - Software Update - 1.2.1]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/download/-/media/document-library-folder---kse/2019/05/09/13/57/ba_kostal_interface_ksem---201911.pdf/ KSEM - Modbus\/ Sunspec]&lt;br /&gt;
&lt;br /&gt;
* [https://www.kostal-solar-electric.com/de-de/service-und-support/kontakt/ Kostal - Service Kontakt]&lt;br /&gt;
&lt;br /&gt;
== Einbindung in das Netzwerk ==&lt;br /&gt;
&lt;br /&gt;
Als Grundlage ist der Plenticore mit dem LAN zu verbinden, wodurch er eine TCP/IP Adresse per DHCP bekommt. Diese ist dann entweder am Display des Plenticore abzulesen, oder über die Oberfläche des Routers zu ermitteln.&lt;br /&gt;
&lt;br /&gt;
Das gleiche gilt für den BYD Speicher, der jedoch zusätzlich auch über WLAN verfügt. Eine Netzwerkanbindung des Speichers ist beim Plenticore nicht zwingend notwendig, da der Plenticore mit dem Speicher über eine RS-485 Schnittstelle kommuniziert. Bei dieser Anbindung werden jedoch noch nicht alle möglichen Werte aus dem Speicher ausgelesen. Später wird hierzu jedoch noch mehr geschrieben, um alle Möglichkeiten offen zu halten.&lt;br /&gt;
&lt;br /&gt;
Der KSEM kann ebenfalls auch direkt per LAN ausgelesen werden, was jedoch ebenfalls nicht zwingend notwendig ist. Eine Kommunikation des KSEM mit dem Plenticore erfolgt über zwei mögliche Wege. Beim Betrieb mit Speicher ist zwingend die RS485 Schnittstelle erforderlich, über die auch der Plenticore alle Werte übermittelt bekommt. Auch diese sind dann am Plenticore abfragbar. Der zweite Weg wäre dann über die LAN Verbindung, bei der jedoch kein Speicher am Plenticore konfigurierbar ist.&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen FHEM Umfeld ==&lt;br /&gt;
&lt;br /&gt;
=== Alle Geräte müssen mit TCP/IP erreichbar sein ===&lt;br /&gt;
&lt;br /&gt;
=== Alle Module sollten auf einem aktuellen Stand sein ===&lt;br /&gt;
&lt;br /&gt;
=== Python ===&lt;br /&gt;
&lt;br /&gt;
==== Ein Python 3 sollte vorhanden sein ====&lt;br /&gt;
Wenn man die erweiterten Funktionalitäten, wie Statistiken, Speicher auslesen und später auch das Setzen von Werten im Plenticore, verwenden möchte.&lt;br /&gt;
&lt;br /&gt;
==== Es müssen folgende Python Module vorhanden sein ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
python3-pip&lt;br /&gt;
&lt;br /&gt;
pip3 install pycryptodome&lt;br /&gt;
pip3 install -U fhem&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Eine LogDB/LogDBRep sollte bereits vorhanden sein, was hier nicht weiter erklärt wird. ===&lt;br /&gt;
&lt;br /&gt;
=== Verwendete Module ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- Modbus&lt;br /&gt;
- HTTPMOD&lt;br /&gt;
- expandJSON&lt;br /&gt;
- DbLog&lt;br /&gt;
- DbRep&lt;br /&gt;
- dummy&lt;br /&gt;
- Shelly&lt;br /&gt;
- HourCounter&lt;br /&gt;
- readingsGroup&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Einbindung in FHEM: Überblick ==&lt;br /&gt;
&lt;br /&gt;
=== Hardware Anbindung (alles über LAN) ===&lt;br /&gt;
&lt;br /&gt;
==== Kostal Plenticore Plus ====&lt;br /&gt;
===== Kostal Plenticore Plus die Basis information (Modbus/TCP) =====&lt;br /&gt;
Der Kostal Plenticore wird mittels des Moduls MODBUS eingebunden. Dazu gilt zunächst die folgende Konfiguration als Basis, die am Display des Plenticore oder auch in der Kostal Dokumentation zu entnehmen ist.&lt;br /&gt;
====== Plenticore Modbus Definition ======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GeräteId  : 71&lt;br /&gt;
IP-Adresse: &amp;lt;IP-Adresse&amp;gt;&lt;br /&gt;
Port      : 1502&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Modbus Timing ======&lt;br /&gt;
Das Gerät aktualisiert sich im Abstand von 60 Sekunden durch den stetigen Modbus/TCP Datenstrom. Der Plenticore ist als Modbus Master implementiert und sendet somit alle Daten permanent ins Netzwerk. &lt;br /&gt;
&lt;br /&gt;
Die Zeit kann auch verändert werden, jedoch sollte sie nicht zu kurz gewählt sein. &lt;br /&gt;
&lt;br /&gt;
====== RAW Definition des konfigurations Dummy ======&lt;br /&gt;
Diese Dummy soll alle Konfigurationsparameter halten, auf die dann die anderen Geräte Definitionen zentral zugreifen. Hier können auch default Namen und Vorschläge für Werte in Form von Slidern und Auswahllisten hinterlegt werden.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Anlage_1_config dummy&lt;br /&gt;
attr PV_Anlage_1_config DbLogExclude .*&lt;br /&gt;
attr PV_Anlage_1_config alias PV_Anlage_1_config&lt;br /&gt;
attr PV_Anlage_1_config comment Steht das reading module_*_count auf 0 wird diese Ausrichtung nicht berücksichtigt\&lt;br /&gt;
Passworte zu dieser Konfiguration liegen im Dateiverzeichnis ~./python/pwd_*.json\&lt;br /&gt;
\&lt;br /&gt;
Korrekturkurven:\&lt;br /&gt;
         Steilheit  Parallel\&lt;br /&gt;
                    verschiebung\&lt;br /&gt;
tempk      -0.39      25\&lt;br /&gt;
cloudk     -0.65       0\&lt;br /&gt;
raink      -0.30       0\&lt;br /&gt;
Der Slider für die Steilheit wird mit - k/100 umgerechnet. 39 ==&amp;gt; -0.39&lt;br /&gt;
attr PV_Anlage_1_config event-on-change-reading .*&lt;br /&gt;
attr PV_Anlage_1_config group PV Eigenverbrauch&lt;br /&gt;
attr PV_Anlage_1_config icon solar_icon&lt;br /&gt;
attr PV_Anlage_1_config readingList IP-Address_Plenticore IP-Address_BYD IP-Address_KSEM IP-Address_FHEM module_1_active module_2_active module_3_active module_1_name module_2_name module_3_name module_1_direction module_2_direction module_3_direction module_1_count module_2_count module_3_count module_1_power module_2_power module_3_power module_1_plain module_2_plain module_3_plain forecast_cloudk forecast_cloudk_base forecast_raink forecast_raink_base forecast_tempk forecast_tempk_base forecast_factor&lt;br /&gt;
attr PV_Anlage_1_config room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Anlage_1_config setList IP-Address_Plenticore IP-Address_BYD IP-Address_KSEM IP-Address_FHEM module_1_name:East,SouthEast,South,SouthWest,West module_2_name:East,SouthEast,South,SouthWest,West module_3_name:East,SouthEast,South,SouthWest,West module_1_direction:slider,-90,5,+90 module_2_direction:slider,-90,5,90 module_3_direction:slider,-90,5,90 module_1_count:slider,0,1,40 module_2_count:slider,0,1,40 module_3_count:slider,0,1,40 module_1_power:slider,250,10,400 module_2_power:slider,250,10,400 module_3_power:slider,250,10,400 module_1_plain:slider,15,1,45 module_2_plain:slider,15,1,45 module_3_plain:slider,15,1,45 forecast_cloudk:slider,0,1,100 forecast_cloudk_base:slider,0,1,10 forecast_raink:slider,0,1,100 forecast_raink_base:slider,0,1,10 forecast_tempk:slider,0,1,100 forecast_tempk_base:slider,10,1,30 forecast_factor:1,1.5,2,2.5,3,3.5,4,4.5,5&lt;br /&gt;
attr PV_Anlage_1_config sortby 06&lt;br /&gt;
attr PV_Anlage_1_config verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== RAW Definition des Wechselrichters ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Anlage_1 ModbusAttr 71 60 &amp;lt;IP-Address_Plenticore&amp;gt;:1502 TCP&lt;br /&gt;
attr PV_Anlage_1 DbLogExclude .*&lt;br /&gt;
attr PV_Anlage_1 DbLogInclude Act_state_of_charge,Actual_battery_charge_-minus_or_discharge_-plus_Power,Actual_battery_charge_usable_Power,Battery_temperature,Home_own_consumption_from_PV,Home_own_consumption_from_battery,Home_own_consumption_from_grid,Inverter_state,Power_DC1,Power_DC2,Power_DC_Sum,Total_DC_Power,Total_DC_Power_Max,Total_PV_Power_reserve,Voltage_DC1,Voltage_DC2,.*_yield,Solar_.*,Statistic_.*&lt;br /&gt;
attr PV_Anlage_1 alias PV_Einspeisung&lt;br /&gt;
attr PV_Anlage_1 comment Kostal Plenticore 10 Plus mit BYD Speicher&lt;br /&gt;
attr PV_Anlage_1 dev-h-defFormat %.2f&lt;br /&gt;
attr PV_Anlage_1 dev-h-defLen 2&lt;br /&gt;
attr PV_Anlage_1 dev-h-defPoll 1&lt;br /&gt;
attr PV_Anlage_1 dev-h-defRevRegs 1&lt;br /&gt;
attr PV_Anlage_1 dev-h-defUnpack f&amp;gt;&lt;br /&gt;
attr PV_Anlage_1 dev-type-STR-format %s&lt;br /&gt;
attr PV_Anlage_1 dev-type-STR-len 8&lt;br /&gt;
attr PV_Anlage_1 dev-type-STR-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 dev-type-STR-unpack a*&lt;br /&gt;
attr PV_Anlage_1 event-on-change-reading statistics_.*,Statistic_.*,Act_state_of_charge,Actual_battery_charge_.*,Battery_temperature,Home_own_consumption_from_.*,Inverter_state,Power_DC1,Power_DC2,Power_DC_Sum,Total_DC_Power,Total_DC_Power_Max,Total_PV_Power_reserve,Voltage_DC1,Voltage_DC2,.*_yield,Solar_.*&lt;br /&gt;
attr PV_Anlage_1 group PV Eigenverbrauch&lt;br /&gt;
attr PV_Anlage_1 icon sani_solar&lt;br /&gt;
attr PV_Anlage_1 obj-h100-reading Total_DC_Power&lt;br /&gt;
attr PV_Anlage_1 obj-h104-format %s&lt;br /&gt;
attr PV_Anlage_1 obj-h104-reading State_of_energy_manager&lt;br /&gt;
attr PV_Anlage_1 obj-h104-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 obj-h104-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h106-reading Home_own_consumption_from_battery&lt;br /&gt;
attr PV_Anlage_1 obj-h108-reading Home_own_consumption_from_grid&lt;br /&gt;
attr PV_Anlage_1 obj-h110-reading Total_home_consumption_Battery&lt;br /&gt;
attr PV_Anlage_1 obj-h112-reading Total_home_consumption_Grid&lt;br /&gt;
attr PV_Anlage_1 obj-h114-reading Total_home_consumption_PV&lt;br /&gt;
attr PV_Anlage_1 obj-h116-reading Home_own_consumption_from_PV&lt;br /&gt;
attr PV_Anlage_1 obj-h118-reading Total_home_consumption&lt;br /&gt;
attr PV_Anlage_1 obj-h120-reading Isolation_resistance&lt;br /&gt;
attr PV_Anlage_1 obj-h122-reading Power_limit_from_EVU&lt;br /&gt;
attr PV_Anlage_1 obj-h124-reading Total_home_consumption_rate&lt;br /&gt;
attr PV_Anlage_1 obj-h14-reading Inverter_serial_number&lt;br /&gt;
attr PV_Anlage_1 obj-h14-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h144-reading Worktime&lt;br /&gt;
attr PV_Anlage_1 obj-h150-reading Actual_cos_phi&lt;br /&gt;
attr PV_Anlage_1 obj-h152-reading Grid_frequency&lt;br /&gt;
attr PV_Anlage_1 obj-h154-reading Current_Phase_1&lt;br /&gt;
attr PV_Anlage_1 obj-h156-reading Active_power_Phase_1&lt;br /&gt;
attr PV_Anlage_1 obj-h158-reading Voltage_Phase_1&lt;br /&gt;
attr PV_Anlage_1 obj-h160-reading Current_Phase_2&lt;br /&gt;
attr PV_Anlage_1 obj-h162-reading Active_power_Phase_2&lt;br /&gt;
attr PV_Anlage_1 obj-h164-reading Voltage_Phase_2&lt;br /&gt;
attr PV_Anlage_1 obj-h166-reading Current_Phase_3&lt;br /&gt;
attr PV_Anlage_1 obj-h168-reading Active_power_Phase_3&lt;br /&gt;
attr PV_Anlage_1 obj-h170-reading Voltage_Phase_3&lt;br /&gt;
attr PV_Anlage_1 obj-h172-reading Total_AC_active_power&lt;br /&gt;
attr PV_Anlage_1 obj-h174-reading Total_AC_reactive_power&lt;br /&gt;
attr PV_Anlage_1 obj-h178-reading Total_AC_apparent_power&lt;br /&gt;
attr PV_Anlage_1 obj-h190-reading Battery_charge_current&lt;br /&gt;
attr PV_Anlage_1 obj-h194-format %.0f&lt;br /&gt;
attr PV_Anlage_1 obj-h194-reading Number_of_battery_cycles&lt;br /&gt;
attr PV_Anlage_1 obj-h200-reading Actual_battery_charge_-minus_or_discharge_-plus_current&lt;br /&gt;
attr PV_Anlage_1 obj-h202-reading PSSB_fuse_state&lt;br /&gt;
attr PV_Anlage_1 obj-h208-format %.0f&lt;br /&gt;
attr PV_Anlage_1 obj-h208-reading Battery_ready_flag&lt;br /&gt;
attr PV_Anlage_1 obj-h210-reading Act_state_of_charge&lt;br /&gt;
attr PV_Anlage_1 obj-h212-reading Battery_state&lt;br /&gt;
attr PV_Anlage_1 obj-h214-reading Battery_temperature&lt;br /&gt;
attr PV_Anlage_1 obj-h216-reading Battery_voltage&lt;br /&gt;
attr PV_Anlage_1 obj-h218-reading Cos_phi_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h220-reading Frequency_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h222-reading Current_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h224-reading Active_power_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h226-reading Reactive_power_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h228-reading Apparent_power_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h230-reading Voltage_phase_1_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h232-reading Current_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h234-reading Active_power_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h236-reading Reactive_power_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h238-reading Apparent_power_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h240-reading Voltage_phase_2_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h242-reading Current_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h244-reading Active_power_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h246-reading Reactive_power_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h248-reading Apparent_power_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h250-reading Voltage_phase_3_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h252-reading Total_active_power_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h254-reading Total_reactive_power_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h256-reading Total_apparent_power_(powermeter)&lt;br /&gt;
attr PV_Anlage_1 obj-h258-reading Current_DC1&lt;br /&gt;
attr PV_Anlage_1 obj-h260-reading Power_DC1&lt;br /&gt;
attr PV_Anlage_1 obj-h266-reading Voltage_DC1&lt;br /&gt;
attr PV_Anlage_1 obj-h268-reading Current_DC2&lt;br /&gt;
attr PV_Anlage_1 obj-h270-reading Power_DC2&lt;br /&gt;
attr PV_Anlage_1 obj-h276-reading Voltage_DC2&lt;br /&gt;
attr PV_Anlage_1 obj-h278-reading Current_DC3&lt;br /&gt;
attr PV_Anlage_1 obj-h280-reading Power_DC3&lt;br /&gt;
attr PV_Anlage_1 obj-h286-reading Voltage_DC3&lt;br /&gt;
attr PV_Anlage_1 obj-h320-reading Total_yield&lt;br /&gt;
attr PV_Anlage_1 obj-h322-reading Daily_yield&lt;br /&gt;
attr PV_Anlage_1 obj-h324-reading Yearly_yield&lt;br /&gt;
attr PV_Anlage_1 obj-h326-reading Monthly_yield&lt;br /&gt;
attr PV_Anlage_1 obj-h38-reading Software-Version_Maincontroller_(MC)&lt;br /&gt;
attr PV_Anlage_1 obj-h38-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h384-len 16&lt;br /&gt;
attr PV_Anlage_1 obj-h384-reading Inverter_network_name&lt;br /&gt;
attr PV_Anlage_1 obj-h384-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h420-reading IP-address&lt;br /&gt;
attr PV_Anlage_1 obj-h420-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h428-reading IP-subnetmask&lt;br /&gt;
attr PV_Anlage_1 obj-h428-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h436-reading IP-gateway&lt;br /&gt;
attr PV_Anlage_1 obj-h436-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h446-reading IP-DNS1&lt;br /&gt;
attr PV_Anlage_1 obj-h446-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h454-reading IP-DNS2&lt;br /&gt;
attr PV_Anlage_1 obj-h454-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h46-reading Software-Version_IO-Controller_(IOC)&lt;br /&gt;
attr PV_Anlage_1 obj-h46-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h514-len 1&lt;br /&gt;
attr PV_Anlage_1 obj-h514-reading Battery_actual_SOC&lt;br /&gt;
attr PV_Anlage_1 obj-h517-reading Battery_Manufacturer&lt;br /&gt;
attr PV_Anlage_1 obj-h517-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h525-format %c&lt;br /&gt;
attr PV_Anlage_1 obj-h525-reading Battery_Model_ID&lt;br /&gt;
attr PV_Anlage_1 obj-h525-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h527-format %c&lt;br /&gt;
attr PV_Anlage_1 obj-h527-reading Battery_Serial_Number&lt;br /&gt;
attr PV_Anlage_1 obj-h529-len 4&lt;br /&gt;
attr PV_Anlage_1 obj-h529-reading Work_Capacity&lt;br /&gt;
attr PV_Anlage_1 obj-h529-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h531-format %.0f&lt;br /&gt;
attr PV_Anlage_1 obj-h531-reading Inverter_Max_Power&lt;br /&gt;
attr PV_Anlage_1 obj-h531-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h535-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 obj-h535-unpack n&lt;br /&gt;
attr PV_Anlage_1 obj-h551-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 obj-h559-revRegs 0&lt;br /&gt;
attr PV_Anlage_1 obj-h56-format %.0f&lt;br /&gt;
attr PV_Anlage_1 obj-h56-reading Inverter_state&lt;br /&gt;
attr PV_Anlage_1 obj-h56-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h575-len 1&lt;br /&gt;
attr PV_Anlage_1 obj-h575-reading Inverter_Generation_Power_(actual)&lt;br /&gt;
attr PV_Anlage_1 obj-h577-len 2&lt;br /&gt;
attr PV_Anlage_1 obj-h577-reading Generation_Energy&lt;br /&gt;
attr PV_Anlage_1 obj-h577-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h578-reading Total_energy&lt;br /&gt;
attr PV_Anlage_1 obj-h582-reading Actual_battery_charge-discharge_power&lt;br /&gt;
attr PV_Anlage_1 obj-h586-format %s&lt;br /&gt;
attr PV_Anlage_1 obj-h586-reading Battery_Firmware&lt;br /&gt;
attr PV_Anlage_1 obj-h586-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h588-format %s&lt;br /&gt;
attr PV_Anlage_1 obj-h588-len 1&lt;br /&gt;
attr PV_Anlage_1 obj-h588-reading Battery_Type&lt;br /&gt;
attr PV_Anlage_1 obj-h588-unpack N&lt;br /&gt;
attr PV_Anlage_1 obj-h6-reading Inverter_article_number&lt;br /&gt;
attr PV_Anlage_1 obj-h6-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h768-len 32&lt;br /&gt;
attr PV_Anlage_1 obj-h768-reading Productname&lt;br /&gt;
attr PV_Anlage_1 obj-h768-type STR&lt;br /&gt;
attr PV_Anlage_1 obj-h800-len 32&lt;br /&gt;
attr PV_Anlage_1 obj-h800-reading Power_class&lt;br /&gt;
attr PV_Anlage_1 obj-h800-type STR&lt;br /&gt;
attr PV_Anlage_1 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Anlage_1 sortby 01&lt;br /&gt;
attr PV_Anlage_1 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TH ALIGN=\&amp;quot;MIDDLE\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;Batterie %s&amp;lt;/TH&amp;gt;\&lt;br /&gt;
  &amp;lt;TH ALIGN=\&amp;quot;MIDDLE\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;aktuell&amp;lt;/TH&amp;gt;\&lt;br /&gt;
  &amp;lt;TH ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;Hausverbrauch&amp;lt;/TH&amp;gt;\&lt;br /&gt;
  &amp;lt;TH ALIGN=\&amp;quot;MIDDLE\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;Erträge&amp;lt;/TH&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD ALIGN=\&amp;quot;MIDDLE\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;\&lt;br /&gt;
    Leistung:  %04d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    Temp.: %02.1f °C&amp;lt;br&amp;gt;\&lt;br /&gt;
    Ladung total: %2d %%&amp;lt;br&amp;gt;\&lt;br /&gt;
    Ladung Res.: %04d Wh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;\&lt;br /&gt;
    DC total: %05d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    &amp;lt;br&amp;gt;\&lt;br /&gt;
    &amp;lt;br&amp;gt;\&lt;br /&gt;
    PV reserve: %05d W\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;\&lt;br /&gt;
    von PV: %05d W &amp;lt;br&amp;gt;\&lt;br /&gt;
    von Batterie: %05d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    vom Netz: %05d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    ins Haus: %05d W&amp;lt;br&amp;gt;\&lt;br /&gt;
    Netz: %05d W\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;20\&amp;quot;&amp;gt;\&lt;br /&gt;
    Tag: %05d KWh &amp;lt;br&amp;gt;\&lt;br /&gt;
    Monat: %05d KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Jahr: %05d KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
    Total: %05d KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; , \&lt;br /&gt;
(ReadingsVal($name,&amp;quot;Actual_battery_charge_-minus_or_discharge_-plus_Power&amp;quot;,0) lt 0) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;Laden&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Entladen&amp;lt;/span&amp;gt;&amp;quot; ,\&lt;br /&gt;
\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Actual_battery_charge_-minus_or_discharge_-plus_Power&amp;quot;,0),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Battery_temperature&amp;quot;,0) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Act_state_of_charge&amp;quot;,0) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Actual_battery_charge_usable_Power&amp;quot;,0) ,\&lt;br /&gt;
\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Power_DC_Sum&amp;quot;,&amp;quot;0&amp;quot;),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Total_PV_Power_reserve&amp;quot;,&amp;quot;0&amp;quot;),\&lt;br /&gt;
\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Home_own_consumption_from_PV&amp;quot;,0) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Home_own_consumption_from_battery&amp;quot;,0) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Home_own_consumption_from_grid&amp;quot;,0),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Home_own_consumption_from_PV&amp;quot;,0) +ReadingsVal($name,&amp;quot;Home_own_consumption_from_battery&amp;quot;,0)+ReadingsVal($name,&amp;quot;Home_own_consumption_from_grid&amp;quot;,0),\&lt;br /&gt;
ReadingsVal($name,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0),\&lt;br /&gt;
\&lt;br /&gt;
round(ReadingsVal($name,&amp;quot;Daily_yield&amp;quot;,0)/1000 ,0),\&lt;br /&gt;
round(ReadingsVal($name,&amp;quot;Monthly_yield&amp;quot;,0)/1000 ,0) ,\&lt;br /&gt;
round(ReadingsVal($name,&amp;quot;Yearly_yield&amp;quot;,0)/1000 ,0) ,\&lt;br /&gt;
round(ReadingsVal($name,&amp;quot;Total_yield&amp;quot;,0)/1000 ,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr PV_Anlage_1 userReadings Power_DC_Sum:Total_DC_Power.* { ReadingsVal($NAME,&amp;quot;Power_DC1&amp;quot;,&amp;quot;0&amp;quot;)+ReadingsVal($NAME,&amp;quot;Power_DC2&amp;quot;,&amp;quot;0&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
Total_PV_Power_reserve:Total_DC_Power.* {my $reserve = ReadingsVal($NAME,&amp;quot;Power_DC_Sum&amp;quot;,&amp;quot;0&amp;quot;) * 0.90 - ReadingsVal($NAME,&amp;quot;Home_own_consumption_from_PV&amp;quot;,&amp;quot;0&amp;quot;);;;; ($reserve lt 0)?0:round($reserve,3)  },\&lt;br /&gt;
\&lt;br /&gt;
Total_DC_Power_Max:Total_DC_Power.* { my $Bat_out = (ReadingsVal($NAME,&amp;quot;Actual_battery_charge_-minus_or_discharge_-plus_current&amp;quot;,&amp;quot;0&amp;quot;)*ReadingsVal($NAME,&amp;quot;Battery_voltage&amp;quot;,&amp;quot;0&amp;quot;));;;; ($Bat_out gt 0)?ReadingsVal($NAME,&amp;quot;Power_DC_Sum&amp;quot;,&amp;quot;0&amp;quot;) + $Bat_out :ReadingsVal($NAME,&amp;quot;Power_DC_Sum&amp;quot;,&amp;quot;0&amp;quot;) },\&lt;br /&gt;
\&lt;br /&gt;
Actual_battery_charge_-minus_or_discharge_-plus_Power:Actual_battery_charge_-minus_or_discharge_-plus_current.* {round((ReadingsVal($NAME,&amp;quot;Actual_battery_charge_-minus_or_discharge_-plus_current&amp;quot;,&amp;quot;0&amp;quot;)*ReadingsVal($NAME,&amp;quot;Battery_voltage&amp;quot;,&amp;quot;0&amp;quot;)),0)},\&lt;br /&gt;
\&lt;br /&gt;
Actual_battery_charge_usable_Power:Act_state_of_charge.* {my $x = (8960*(ReadingsVal($NAME,&amp;quot;Act_state_of_charge&amp;quot;,&amp;quot;0&amp;quot;)-10)/100);;;; ($x lt 0)?0:round($x,0) },\&lt;br /&gt;
\&lt;br /&gt;
statistics_clean:statistics_output.* { my $x =  ReadingsVal($NAME,&amp;quot;statistics_output&amp;quot;,0);;;; $x =~ s/&amp;quot;moduleid&amp;quot;: &amp;quot;scb:statistic:EnergyFlow&amp;quot;, |, &amp;quot;moduleid&amp;quot;: &amp;quot;scb:statistic:EnergyFlow&amp;quot;|&amp;quot;processdata&amp;quot;: \[//g;;;; $x =~ s/id&amp;quot;: &amp;quot;|, &amp;quot;unit&amp;quot;: &amp;quot;&amp;quot;, &amp;quot;value&amp;quot;|^\[|\]\}\]$//g;;;; $x =~ s/moduleid/statistics_00_moduleid/g;;;; $x =~ s/processdata/statistics/g;;;; $x =~ s/\}\, \{/\, /g;;;; $x =~ s/\{\{/\{/g;;;; return $x }&lt;br /&gt;
attr PV_Anlage_1 verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Userreadings ======&lt;br /&gt;
Um später einige Abfragen und Diagramme einfacher zu erstellen wurden einige userreadings erstellt, die bereits bei der RAW Definition mit vorhanden sind. Während der Integration in FHEM und der Konfiguration kann es hierdurch jedoch noch Fehlermeldungen im FHEM Log geben, da noch nicht alle Werte vorhanden sind. Dies betrifft insbesondere die Statistics_* readings, die durch ein Python Skript später erzeugt werden.&lt;br /&gt;
&lt;br /&gt;
Power_DC_Sum&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Dies berechnet direkt die Summe der DC-Leistung. Wenn der Plenticore einen Speicher hat, wird dieser am String 3 angeschlossen,&lt;br /&gt;
   sollte also kein Speicher vorhanden sein muss man hier den dritten String auch noch addieren.&lt;br /&gt;
Total_PV_Power_reserve&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Hier wird ein reading erstellt, dass als Information über die verwendbare Reserve dient. Die Leistung, die in den Speicher geht&lt;br /&gt;
   sollte man nämlich besser sofort verbrauchen, anstatt es erst zu speicher. Die 0.90 ist ein circa Wirkungsgrad, um von DC- auf AC-Leistung zu kommen.&lt;br /&gt;
   Der Total_PV_Power_reserve Wert kann gerne nach eigenen Belangen kalkuliert werden.&lt;br /&gt;
Total_DC_Power_Max&lt;br /&gt;
   Trigger: Total_DC_Power.*&lt;br /&gt;
   Um die Batterieleistung mit zu berücksichtigen wird dieser Momentan Wert ermittelt.&lt;br /&gt;
Actual_battery_charge_-minus_or_discharge_-plus_Power&lt;br /&gt;
   Trigger: Actual_battery_charge_-minus_or_discharge_-plus_current.*&lt;br /&gt;
   Berechnung der Batterie Leistung aus Spannung und Strom , der wert kann positiv oder negativ sein, je nach dem ob geladen oder entladen wird.&lt;br /&gt;
Actual_battery_charge_usable_Power&lt;br /&gt;
   Trigger: Act_state_of_charge.*&lt;br /&gt;
   Dieser Wert gibt an, wieviel Leistung im Speicher vorhanden ist, reduziert um 10% Verluste. An dieser Stelle muss die Nennleistung des Speichers&lt;br /&gt;
   eingetragen werden, da diese noch nicht ausgelesen werden kann. Obwohl es im &amp;quot;Battery_Type 892941625&amp;quot; stecken könnte. 8929 &amp;gt;&amp;gt; 8.93 KW ???&lt;br /&gt;
statistics_clean&lt;br /&gt;
   Trigger: statistics_output.*&lt;br /&gt;
   Dies ist ein temporäres reading, das nur als zwischen Schritt für die Erstellung der Statistics_* readings verwendet wird. Befüllt wird zuerst&lt;br /&gt;
   das reading statistics_output durch ein regelmäßig laufendes Python Skript.&lt;br /&gt;
   Wer keine Statistiken haben möchte kann das einfach entfernen.&lt;br /&gt;
statistics_output&lt;br /&gt;
   Trigger: externes Python Skript&lt;br /&gt;
   Das userreading wird über ein Python Skript mit Daten gefüllt und dient als Trigger für statistics_clean&lt;br /&gt;
&lt;br /&gt;
====== statistics_clean in readings umwandeln ======&lt;br /&gt;
Die Statistiken des Plenticore werden über ein Python Skript in das reading statistics_output geschrieben. Durch ein userreading wird daraus das JSON vereinfacht und in statistics_claen übertragen. Im letzten Schritt wandelt das expandJSON den JSON String in einzelne readings um.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Plenticore_Statistics expandJSON PV_Anlage_1:statistics_clean:.\{.*}&lt;br /&gt;
attr Plenticore_Statistics DbLogExclude .*&lt;br /&gt;
attr Plenticore_Statistics alias Plenticore_Statistics&lt;br /&gt;
attr Plenticore_Statistics comment Das Device wird über ein Python Skript im reading output befüllt.\&lt;br /&gt;
&lt;br /&gt;
attr Plenticore_Statistics disable 0&lt;br /&gt;
attr Plenticore_Statistics room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Kostal Plenticore Plus die Statistiken (über Python Skript) =====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
&lt;br /&gt;
====== Plenticore API ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Dateiverzeichnis ======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/fhem&lt;br /&gt;
/opt/fhem/python/pwd_fhem.json&lt;br /&gt;
/opt/fhem/python/pwd_plenticore.json&lt;br /&gt;
/opt/fhem/python/bin&lt;br /&gt;
/opt/fhem/python/bin/plenticore_statistic.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Python 3 ======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ which python3&lt;br /&gt;
/usr/bin/python3&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ python3 --version&lt;br /&gt;
Python 3.7.3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== plenticore_statistic.py ======&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ cat plenticore_statistic.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import random&lt;br /&gt;
import string&lt;br /&gt;
import base64&lt;br /&gt;
import json&lt;br /&gt;
import requests&lt;br /&gt;
import hashlib&lt;br /&gt;
import os&lt;br /&gt;
import hmac&lt;br /&gt;
from Crypto.Cipher import AES&lt;br /&gt;
import binascii&lt;br /&gt;
&lt;br /&gt;
import fhem&lt;br /&gt;
import asyncio&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
plenticore = sys.argv[1]&lt;br /&gt;
web        = sys.argv[2]&lt;br /&gt;
request    = &#039;/processdata/scb:statistic:EnergyFlow&#039; &lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_plenticore.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
USER_TYPE = credentials[&amp;quot;username&amp;quot;]&lt;br /&gt;
PASSWD = credentials[&amp;quot;password&amp;quot;]&lt;br /&gt;
BASE_URL = &amp;quot;http://&amp;quot; + plenticore + &amp;quot;/api/v1&amp;quot;&lt;br /&gt;
AUTH_START = &amp;quot;/auth/start&amp;quot;&lt;br /&gt;
AUTH_FINISH = &amp;quot;/auth/finish&amp;quot;&lt;br /&gt;
AUTH_CREATE_SESSION = &amp;quot;/auth/create_session&amp;quot;&lt;br /&gt;
ME = &amp;quot;/auth/me&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def randomString(stringLength):&lt;br /&gt;
    letters = string.ascii_letters&lt;br /&gt;
    return &#039;&#039;.join(random.choice(letters) for i in range(stringLength))&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
u = randomString(12)&lt;br /&gt;
u = base64.b64encode(u.encode(&#039;utf-8&#039;)).decode(&#039;utf-8&#039;)&lt;br /&gt;
&lt;br /&gt;
step1 = {&lt;br /&gt;
  &amp;quot;username&amp;quot;: USER_TYPE,&lt;br /&gt;
  &amp;quot;nonce&amp;quot;: u&lt;br /&gt;
}&lt;br /&gt;
step1 = json.dumps(step1)&lt;br /&gt;
&lt;br /&gt;
url = BASE_URL + AUTH_START&lt;br /&gt;
headers = {&#039;Content-type&#039;: &#039;application/json&#039;, &#039;Accept&#039;: &#039;application/json&#039;}&lt;br /&gt;
response = requests.post(url, data=step1, headers=headers)&lt;br /&gt;
response = json.loads(response.text)&lt;br /&gt;
i = response[&#039;nonce&#039;]&lt;br /&gt;
e = response[&#039;transactionId&#039;]&lt;br /&gt;
o = response[&#039;rounds&#039;]&lt;br /&gt;
a = response[&#039;salt&#039;]&lt;br /&gt;
bitSalt = base64.b64decode(a)&lt;br /&gt;
&lt;br /&gt;
def getPBKDF2Hash(password, bytedSalt, rounds):&lt;br /&gt;
    return hashlib.pbkdf2_hmac(&#039;sha256&#039;, password.encode(&#039;utf-8&#039;), bytedSalt, rounds)&lt;br /&gt;
&lt;br /&gt;
r = getPBKDF2Hash(PASSWD,bitSalt,o)&lt;br /&gt;
s = hmac.new(r, &amp;quot;Client Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
c = hmac.new(r, &amp;quot;Server Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
_ = hashlib.sha256(s).digest()&lt;br /&gt;
d = &amp;quot;n=user,r=&amp;quot;+u+&amp;quot;,r=&amp;quot;+i+&amp;quot;,s=&amp;quot;+a+&amp;quot;,i=&amp;quot;+str(o)+&amp;quot;,c=biws,r=&amp;quot;+i&lt;br /&gt;
g = hmac.new(_, d.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
p = hmac.new(c, d.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
f = bytes(a ^ b for (a, b) in zip(s, g))&lt;br /&gt;
proof = base64.b64encode(f).decode(&#039;utf-8&#039;)&lt;br /&gt;
&lt;br /&gt;
step2 = {&lt;br /&gt;
  &amp;quot;transactionId&amp;quot;: e,&lt;br /&gt;
  &amp;quot;proof&amp;quot;: proof&lt;br /&gt;
}&lt;br /&gt;
step2 = json.dumps(step2)&lt;br /&gt;
&lt;br /&gt;
url = BASE_URL + AUTH_FINISH&lt;br /&gt;
headers = {&#039;Content-type&#039;: &#039;application/json&#039;, &#039;Accept&#039;: &#039;application/json&#039;}&lt;br /&gt;
response = requests.post(url, data=step2, headers=headers)&lt;br /&gt;
response = json.loads(response.text)&lt;br /&gt;
token = response[&#039;token&#039;]&lt;br /&gt;
signature = response[&#039;signature&#039;]&lt;br /&gt;
&lt;br /&gt;
y = hmac.new(_, &amp;quot;Session Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256)&lt;br /&gt;
y.update(d.encode(&#039;utf-8&#039;))&lt;br /&gt;
y.update(s)&lt;br /&gt;
P = y.digest()&lt;br /&gt;
protocol_key = P&lt;br /&gt;
t = os.urandom(16)&lt;br /&gt;
&lt;br /&gt;
e2 = AES.new(protocol_key,AES.MODE_GCM,t)&lt;br /&gt;
e2, authtag = e2.encrypt_and_digest(token.encode(&#039;utf-8&#039;))&lt;br /&gt;
&lt;br /&gt;
step3 = {&lt;br /&gt;
  &amp;quot;transactionId&amp;quot;: e,&lt;br /&gt;
  &amp;quot;iv&amp;quot;: base64.b64encode(t).decode(&#039;utf-8&#039;),&lt;br /&gt;
  &amp;quot;tag&amp;quot;: base64.b64encode(authtag).decode(&amp;quot;utf-8&amp;quot;),&lt;br /&gt;
  &amp;quot;payload&amp;quot;: base64.b64encode(e2).decode(&#039;utf-8&#039;)&lt;br /&gt;
}&lt;br /&gt;
step3 = json.dumps(step3)&lt;br /&gt;
&lt;br /&gt;
headers = { &#039;Content-type&#039;: &#039;application/json&#039;, &#039;Accept&#039;: &#039;application/json&#039; }&lt;br /&gt;
url = BASE_URL + AUTH_CREATE_SESSION&lt;br /&gt;
response = requests.post(url, data=step3, headers=headers)&lt;br /&gt;
response = json.loads(response.text)&lt;br /&gt;
sessionId = response[&#039;sessionId&#039;]&lt;br /&gt;
&lt;br /&gt;
#create a new header with the new Session-ID for all further requests&lt;br /&gt;
headers = { &#039;Content-type&#039;: &#039;application/json&#039;, &#039;Accept&#039;: &#039;application/json&#039;, &#039;authorization&#039;: &amp;quot;Session &amp;quot; + sessionId }&lt;br /&gt;
url = BASE_URL + ME&lt;br /&gt;
response = requests.get(url = url, headers = headers)&lt;br /&gt;
response = json.loads(response.text)&lt;br /&gt;
authOK = response[&#039;authenticated&#039;]&lt;br /&gt;
if not authOK:&lt;br /&gt;
    print(&amp;quot;authorization NOT OK&amp;quot;)&lt;br /&gt;
    sys.exit()&lt;br /&gt;
&lt;br /&gt;
url = BASE_URL + &amp;quot;/info/version&amp;quot;&lt;br /&gt;
response = requests.get(url = url, headers = headers)&lt;br /&gt;
response = json.loads(response.text)&lt;br /&gt;
swversion = response[&#039;sw_version&#039;]&lt;br /&gt;
apiversion = response[&#039;api_version&#039;]&lt;br /&gt;
hostname = response[&#039;hostname&#039;]&lt;br /&gt;
name = response[&#039;name&#039;]&lt;br /&gt;
print(&amp;quot;Connected to the inverter &amp;quot; + name + &amp;quot;/&amp;quot; + hostname + &amp;quot; with SW-Version &amp;quot; + swversion + &amp;quot; and API-Version &amp;quot; + apiversion)&lt;br /&gt;
&lt;br /&gt;
# Auth OK, now send your desired requests&lt;br /&gt;
&lt;br /&gt;
url = BASE_URL + request&lt;br /&gt;
&lt;br /&gt;
response = requests.get(url = url, headers = headers)&lt;br /&gt;
response = json.loads(response.text)&lt;br /&gt;
&lt;br /&gt;
message  = json.dumps(response)&lt;br /&gt;
&lt;br /&gt;
#print(json.dumps(response, indent=4, sort_keys=True))&lt;br /&gt;
#print(message)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
async def run():&lt;br /&gt;
&lt;br /&gt;
    try:&lt;br /&gt;
        with open(&#039;/opt/fhem/python/pwd_fhem.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
            credentials=json.load(f)&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
    fh = fhem.Fhem(web, protocol=&amp;quot;http&amp;quot;, port=8083, username=credentials[&amp;quot;username&amp;quot;], password=credentials[&amp;quot;password&amp;quot;])&lt;br /&gt;
&lt;br /&gt;
    fh.send_cmd(&amp;quot;setreading PV_Anlage_1 statistics_output &amp;quot; + message)&lt;br /&gt;
&lt;br /&gt;
asyncio.get_event_loop().run_until_complete(run())&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Userreadings ======&lt;br /&gt;
Die userreadings gehören zum Gerät PV_Anlage_1 .&lt;br /&gt;
&lt;br /&gt;
statistics_output&lt;br /&gt;
   Trigger: externes Python Skript&lt;br /&gt;
   Das Python Skript beschreibt im Gerät PV_Anlage_1 das reading statistics_output, das dort dann weiterverarbeitet wird.&lt;br /&gt;
&lt;br /&gt;
====== Passworte ======&lt;br /&gt;
Die Passworte für den Plenticore und den FHEM Zugang liegen in einzelnen JSON Dateien&lt;br /&gt;
&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_plenticore.json&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;,&lt;br /&gt;
    &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Steht auf dem Gehäuse&amp;gt;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_fhem.json&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;username&amp;quot;: &amp;quot;&amp;lt;Ein Fhem Telnet User&amp;gt;&amp;quot;,&lt;br /&gt;
    &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Das Passwort des Users&amp;gt;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Kostal Plenticore Plus die API (über HTTPMOD mit Python Skript Authentifizierung) =====&lt;br /&gt;
Der Plenticore erstellt intern noch diverse Statistiken, die auch über das WebGUI angesehen werden können. Diese werden jedoch nicht über MODBUS/TCP ausgegeben, aber zum Kostal Portal übermittelt, wo man dann bereits in Form von Diagrammen einen schönen Überblick bekommt. Das Ziel ist jedoch die Statistiken lokal im FHEM abzulegen, sie lassen sich nur über die API des Plenticore abfragen.&lt;br /&gt;
Für diesen API Zugang über HTTP steht nun ein neues Gerät zur Verfügung, dass mit HTTPMOD und Python Authentifizierungsskripten die mehrstufige Anmeldung durchführt. Das ganze soll in Zukunft den starren Zugriff auf die Statistiken ablösen und eine Erweiterung zum setzen von Parametern im Plenticore bieten.&lt;br /&gt;
&lt;br /&gt;
====== Umstellungsaufwand ======&lt;br /&gt;
Die erste Folge für einen Umstieg wäre, dass die Statistiken nicht mehr im PV_Anlage_1 Gerät abgelegt werden, da diese ja teil der API Abfrage sind. Das muss dann in den Diagrammen und der Bilanz berücksichtigt werden, da die LogDb Einträge dann unter dem neuen PV_Anlage_1_API Gerät abgelegt werden.&lt;br /&gt;
&lt;br /&gt;
====== Plenticore API ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
http://&amp;lt;IP-Address_Plenticore&amp;gt;/api/v1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Dateiverzeichnis ======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/fhem&lt;br /&gt;
/opt/fhem/python/pwd_fhem.json&lt;br /&gt;
/opt/fhem/python/pwd_plenticore.json&lt;br /&gt;
/opt/fhem/python/bin&lt;br /&gt;
/opt/fhem/python/bin/plenticore_finish.py&lt;br /&gt;
/opt/fhem/python/bin/plenticore_session.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Python 3 ======&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ which python3&lt;br /&gt;
/usr/bin/python3&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ python3 --version&lt;br /&gt;
Python 3.7.3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== plenticore_auth_* Erläuterung ======&lt;br /&gt;
Die folgenden beiden Skripte sind ein Extrakt aus den bisherigen Skripten, ohne die HTTP Aufrufe. Sie dienen nur noch der Generierung von Authentifizierungsschlüsseln. Optimaler Weise müssten sie auch noch nach Perl konvertiert werden, was für später geplant ist.&lt;br /&gt;
Als Übergabeparameter werden aus dem PV_Anlage_1_API Gerät Rückgabewerte der HTTP Aufrufe verwendet.&lt;br /&gt;
&lt;br /&gt;
====== plenticore_auth_finish ======&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ cat plenticore_auth_finish.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import string&lt;br /&gt;
import base64&lt;br /&gt;
import hashlib&lt;br /&gt;
import hmac&lt;br /&gt;
from Crypto.Cipher import AES&lt;br /&gt;
import binascii&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
import json&lt;br /&gt;
import fhem&lt;br /&gt;
&lt;br /&gt;
web          = sys.argv[1]&lt;br /&gt;
randomString = sys.argv[2]&lt;br /&gt;
nonce        = sys.argv[3]&lt;br /&gt;
salt         = sys.argv[4]&lt;br /&gt;
rounds       = sys.argv[5]&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_plenticore.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
PASSWD = credentials[&amp;quot;password&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
u       = randomString&lt;br /&gt;
&lt;br /&gt;
#u       = base64.b64encode(u.encode(&#039;utf-8&#039;)).decode(&#039;utf-8&#039;)&lt;br /&gt;
#print(&amp;quot;randomString: &amp;quot;,u)&lt;br /&gt;
&lt;br /&gt;
i       = nonce&lt;br /&gt;
o       = int(rounds)&lt;br /&gt;
a       = salt&lt;br /&gt;
bitSalt = base64.b64decode(a)&lt;br /&gt;
&lt;br /&gt;
#print(&amp;quot;nonce       : &amp;quot;,i)&lt;br /&gt;
#print(&amp;quot;salt        : &amp;quot;,a)&lt;br /&gt;
#print(&amp;quot;rounds      : &amp;quot;,o)&lt;br /&gt;
&lt;br /&gt;
def getPBKDF2Hash(password, bytedSalt, rounds):&lt;br /&gt;
    return hashlib.pbkdf2_hmac(&#039;sha256&#039;, password.encode(&#039;utf-8&#039;), bytedSalt, rounds)&lt;br /&gt;
&lt;br /&gt;
r = getPBKDF2Hash(PASSWD,bitSalt,o)&lt;br /&gt;
s = hmac.new(r, &amp;quot;Client Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
c = hmac.new(r, &amp;quot;Server Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
_ = hashlib.sha256(s).digest()&lt;br /&gt;
d = &amp;quot;n=user,r=&amp;quot;+u+&amp;quot;,r=&amp;quot;+i+&amp;quot;,s=&amp;quot;+a+&amp;quot;,i=&amp;quot;+str(o)+&amp;quot;,c=biws,r=&amp;quot;+i&lt;br /&gt;
g = hmac.new(_, d.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
p = hmac.new(c, d.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
f = bytes(a ^ b for (a, b) in zip(s, g))&lt;br /&gt;
proof = base64.b64encode(f).decode(&#039;utf-8&#039;)&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_fhem.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
fh = fhem.Fhem(web, protocol=&amp;quot;http&amp;quot;, port=8083, username=credentials[&amp;quot;username&amp;quot;], password=credentials[&amp;quot;password&amp;quot;])&lt;br /&gt;
&lt;br /&gt;
fh.send_cmd(&amp;quot;setreading PV_Anlage_1_API auth_proof &amp;quot; + proof)&lt;br /&gt;
&lt;br /&gt;
#print(&amp;quot;proof       : &amp;quot;,proof)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====== plenticore_auth_session ======&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ cat plenticore_auth_session.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
import string&lt;br /&gt;
import base64&lt;br /&gt;
import hashlib&lt;br /&gt;
import os&lt;br /&gt;
import hmac&lt;br /&gt;
from Crypto.Cipher import AES&lt;br /&gt;
import binascii&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
import json&lt;br /&gt;
import fhem&lt;br /&gt;
&lt;br /&gt;
web          = sys.argv[1]&lt;br /&gt;
randomString = sys.argv[2]&lt;br /&gt;
nonce        = sys.argv[3]&lt;br /&gt;
salt         = sys.argv[4]&lt;br /&gt;
rounds       = sys.argv[5]&lt;br /&gt;
token        = sys.argv[6]&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_plenticore.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
PASSWD = credentials[&amp;quot;password&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
u       = randomString&lt;br /&gt;
i       = nonce&lt;br /&gt;
o       = int(rounds)&lt;br /&gt;
a       = salt&lt;br /&gt;
bitSalt = base64.b64decode(a)&lt;br /&gt;
&lt;br /&gt;
def getPBKDF2Hash(password, bytedSalt, rounds):&lt;br /&gt;
    return hashlib.pbkdf2_hmac(&#039;sha256&#039;, password.encode(&#039;utf-8&#039;), bytedSalt, rounds)&lt;br /&gt;
&lt;br /&gt;
r = getPBKDF2Hash(PASSWD,bitSalt,o)&lt;br /&gt;
&lt;br /&gt;
#print(&amp;quot;randomString: &amp;quot;,u)&lt;br /&gt;
#print(&amp;quot;nonce       : &amp;quot;,i)&lt;br /&gt;
#print(&amp;quot;salt        : &amp;quot;,a)&lt;br /&gt;
#print(&amp;quot;rounds      : &amp;quot;,o)&lt;br /&gt;
#print(&amp;quot;token       : &amp;quot;,token)&lt;br /&gt;
&lt;br /&gt;
s = hmac.new(r, &amp;quot;Client Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256).digest()&lt;br /&gt;
_ = hashlib.sha256(s).digest()&lt;br /&gt;
d = &amp;quot;n=user,r=&amp;quot;+u+&amp;quot;,r=&amp;quot;+i+&amp;quot;,s=&amp;quot;+a+&amp;quot;,i=&amp;quot;+str(o)+&amp;quot;,c=biws,r=&amp;quot;+i&lt;br /&gt;
&lt;br /&gt;
y = hmac.new(_, &amp;quot;Session Key&amp;quot;.encode(&#039;utf-8&#039;), hashlib.sha256)&lt;br /&gt;
y.update(d.encode(&#039;utf-8&#039;))&lt;br /&gt;
y.update(s)&lt;br /&gt;
P = y.digest()&lt;br /&gt;
protocol_key = P&lt;br /&gt;
t = os.urandom(16)&lt;br /&gt;
&lt;br /&gt;
e2          = AES.new(protocol_key,AES.MODE_GCM,t)&lt;br /&gt;
e2, authtag = e2.encrypt_and_digest(token.encode(&#039;utf-8&#039;))&lt;br /&gt;
&lt;br /&gt;
iv      = base64.b64encode(t).decode(&#039;utf-8&#039;)&lt;br /&gt;
authtag = base64.b64encode(authtag).decode(&amp;quot;utf-8&amp;quot;)&lt;br /&gt;
payload = base64.b64encode(e2).decode(&#039;utf-8&#039;)&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    with open(&#039;/opt/fhem/python/pwd_fhem.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
        credentials=json.load(f)&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
fh = fhem.Fhem(web, protocol=&amp;quot;http&amp;quot;, port=8083, username=credentials[&amp;quot;username&amp;quot;], password=credentials[&amp;quot;password&amp;quot;])&lt;br /&gt;
&lt;br /&gt;
fh.send_cmd(&amp;quot;setreading PV_Anlage_1_API auth_iv &amp;quot; + iv)&lt;br /&gt;
fh.send_cmd(&amp;quot;setreading PV_Anlage_1_API auth_authtag &amp;quot; + authtag)&lt;br /&gt;
fh.send_cmd(&amp;quot;setreading PV_Anlage_1_API auth_payload &amp;quot; + payload)&lt;br /&gt;
&lt;br /&gt;
#print(&amp;quot;iv          : &amp;quot;,iv)&lt;br /&gt;
#print(&amp;quot;authtag     : &amp;quot;,authtag)&lt;br /&gt;
#print(&amp;quot;payload     : &amp;quot;,payload)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Ablaufbeschreibung PV_Anlage_1_API ======&lt;br /&gt;
Hier soll ein kurzer Überblick für den Anmeldeablauf geschaffen werden.&lt;br /&gt;
======Automatischer Login mit Sessionaufbau======&lt;br /&gt;
Der Ablauf startet mit dem ersten Aufruf und läuft dann vollautomatisch bis zur Rückgabe der auth_sessionId&lt;br /&gt;
   1. get PV_Anlage_1_API 01/auth/start&lt;br /&gt;
* auth_randomString64 - wird generiert&lt;br /&gt;
* /api/v1/auth/start - HTTP request erfolgt&lt;br /&gt;
* auth_nonce, auth_salt, auth_rounds werden empfangen&lt;br /&gt;
   2. auth_Step1_Message:auth_nonce.* wird getriggert&lt;br /&gt;
* plenticore_auth_finish.py wird ausgeführt&lt;br /&gt;
* auth_proof - wird berechnet&lt;br /&gt;
   3. auth_Step2_Message:auth_proof.* wird getriggert&lt;br /&gt;
* Start von 02_/auth/finish&lt;br /&gt;
   4. get PV_Anlage_1_API 02_/auth/finish&lt;br /&gt;
* /api/v1/auth/finish - HTTP request erfolgt&lt;br /&gt;
* auth_signature, auth_token werden empfangen&lt;br /&gt;
   5. auth_Step3_Message:auth_token.* wird getriggert&lt;br /&gt;
* plenticore_auth_session.py wird ausgeführt&lt;br /&gt;
* auth_iv, auth_authtag, auth_payload - wird berechnet&lt;br /&gt;
   6. auth_Step4_Message:auth_payload.* wird getriggert&lt;br /&gt;
* Start von 03_/auth/session&lt;br /&gt;
   7. get PV_Anlage_1_API 03_/auth/session&lt;br /&gt;
* /api/v1/auth/session - HTTP request erfolgt&lt;br /&gt;
* auth_sessionId wird empfangen&lt;br /&gt;
&lt;br /&gt;
Bei allen folgenden HTTP requests wird nun die erhaltene auth_sessenId übermittelt.&lt;br /&gt;
Bereits Implementierte Abfragen:&lt;br /&gt;
   1. 04_/auth/me&lt;br /&gt;
   2. 05_/info/version&lt;br /&gt;
   3. 06_/auth/logout (läuft noch nicht)&lt;br /&gt;
   4. 20_/processdata/scb_statistic_EnergyFlow&lt;br /&gt;
   5. 21_Modules_List&lt;br /&gt;
Sollte die Session abgelaufen, oder noch kein Login vollzogen worden sein, so wird automatisch eine Login mit Sessionaufbau durchgeführt, jedoch wird bis auf /auth/me der letzte Aufruf nicht wiederholt. Dies liegt an dem momentan etwas komplexen Ablauf beim Sessionaufbau.&lt;br /&gt;
&lt;br /&gt;
====== RAW Definition des PV_Anlage_1_API ======&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Anlage_1_API HTTPMOD http://%IP-Address_Plenticore%/api/v1/auth/me 0&lt;br /&gt;
&lt;br /&gt;
attr PV_Anlage_1_API DbLogExclude .*&lt;br /&gt;
attr PV_Anlage_1_API authRetries 1&lt;br /&gt;
attr PV_Anlage_1_API dontRequeueAfterAuth 1&lt;br /&gt;
attr PV_Anlage_1_API enableControlSet 1&lt;br /&gt;
attr PV_Anlage_1_API enableCookies 1&lt;br /&gt;
attr PV_Anlage_1_API get01Data {&amp;quot;nonce&amp;quot;: &amp;quot;%randomString64%&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API get01Name 01_/auth/start&lt;br /&gt;
attr PV_Anlage_1_API get01URL http://%IP-Address_Plenticore%/api/v1/auth/start&lt;br /&gt;
attr PV_Anlage_1_API get02Data {&amp;quot;transactionId&amp;quot;: &amp;quot;%auth_transactionId%&amp;quot;, &amp;quot;proof&amp;quot;: &amp;quot;%auth_proof%&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API get02Name 02_/auth/finish&lt;br /&gt;
attr PV_Anlage_1_API get02URL http://%IP-Address_Plenticore%/api/v1/auth/finish&lt;br /&gt;
attr PV_Anlage_1_API get03Data {&amp;quot;transactionId&amp;quot;: &amp;quot;%auth_transactionId%&amp;quot;, &amp;quot;iv&amp;quot;: &amp;quot;%auth_iv%&amp;quot;, &amp;quot;tag&amp;quot;: &amp;quot;%auth_authtag%&amp;quot;, &amp;quot;payload&amp;quot;: &amp;quot;%auth_payload%&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API get03Name 03_/auth/create_session&lt;br /&gt;
attr PV_Anlage_1_API get03URL http://%IP-Address_Plenticore%/api/v1/auth/create_session&lt;br /&gt;
attr PV_Anlage_1_API get04Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get04Name 04_/auth/me&lt;br /&gt;
attr PV_Anlage_1_API get04URL http://%IP-Address_Plenticore%/api/v1/auth/me&lt;br /&gt;
attr PV_Anlage_1_API get05Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get05Name 05_/info/version&lt;br /&gt;
attr PV_Anlage_1_API get05URL http://%IP-Address_Plenticore%/api/v1/info/version&lt;br /&gt;
attr PV_Anlage_1_API get06Name 06_/auth/logout&lt;br /&gt;
attr PV_Anlage_1_API get06URL http://%IP-Address_Plenticore%/api/v1/auth/logout&lt;br /&gt;
attr PV_Anlage_1_API get20Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get20Name 20_/processdata/scb_statistic_EnergyFlow&lt;br /&gt;
attr PV_Anlage_1_API get20URL http://%IP-Address_Plenticore%/api/v1/processdata/scb:statistic:EnergyFlow&lt;br /&gt;
attr PV_Anlage_1_API get21Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API get21Name 21_Modules_List&lt;br /&gt;
attr PV_Anlage_1_API get21URL http://%IP-Address_Plenticore%/api/v1/modules&lt;br /&gt;
attr PV_Anlage_1_API get22Header authorization: Session %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API getHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr PV_Anlage_1_API getHeader02 Content-type:application/json, Accept:application/json, Connection:keep-alive&lt;br /&gt;
attr PV_Anlage_1_API group PV Eigenverbrauch&lt;br /&gt;
attr PV_Anlage_1_API icon sani_solar&lt;br /&gt;
attr PV_Anlage_1_API reAuthRegex &amp;quot;authenticated&amp;quot;:false|&amp;quot;processdata&amp;quot;:\[\]&lt;br /&gt;
attr PV_Anlage_1_API reading0100JSON anonymous&lt;br /&gt;
attr PV_Anlage_1_API reading0100Name auth_me_anonymous&lt;br /&gt;
attr PV_Anlage_1_API reading0101JSON role&lt;br /&gt;
attr PV_Anlage_1_API reading0101Name auth_me_role&lt;br /&gt;
attr PV_Anlage_1_API reading0102JSON active&lt;br /&gt;
attr PV_Anlage_1_API reading0102Name auth_me_active&lt;br /&gt;
attr PV_Anlage_1_API reading0103JSON locked&lt;br /&gt;
attr PV_Anlage_1_API reading0103Name auth_me_locked&lt;br /&gt;
attr PV_Anlage_1_API reading0104JSON authenticated&lt;br /&gt;
attr PV_Anlage_1_API reading0104Name auth_me_authenticated&lt;br /&gt;
attr PV_Anlage_1_API reading0105JSON salt&lt;br /&gt;
attr PV_Anlage_1_API reading0105Name auth_salt&lt;br /&gt;
attr PV_Anlage_1_API reading0106JSON transactionId&lt;br /&gt;
attr PV_Anlage_1_API reading0106Name auth_transactionId&lt;br /&gt;
attr PV_Anlage_1_API reading0107JSON rounds&lt;br /&gt;
attr PV_Anlage_1_API reading0107Name auth_rounds&lt;br /&gt;
attr PV_Anlage_1_API reading0108JSON nonce&lt;br /&gt;
attr PV_Anlage_1_API reading0108Name auth_nonce&lt;br /&gt;
attr PV_Anlage_1_API reading0109JSON token&lt;br /&gt;
attr PV_Anlage_1_API reading0109Name auth_token&lt;br /&gt;
attr PV_Anlage_1_API reading0110JSON message&lt;br /&gt;
attr PV_Anlage_1_API reading0111JSON signature&lt;br /&gt;
attr PV_Anlage_1_API reading0111Name auth_signature&lt;br /&gt;
attr PV_Anlage_1_API reading0112JSON sessionId&lt;br /&gt;
attr PV_Anlage_1_API reading0112Name auth_sessionId&lt;br /&gt;
attr PV_Anlage_1_API reading0200JSON api_version&lt;br /&gt;
attr PV_Anlage_1_API reading0200Name info_api_version&lt;br /&gt;
attr PV_Anlage_1_API reading0201JSON sw_version&lt;br /&gt;
attr PV_Anlage_1_API reading0201Name info_sw_version&lt;br /&gt;
attr PV_Anlage_1_API reading0202JSON name&lt;br /&gt;
attr PV_Anlage_1_API reading0202Name info_name&lt;br /&gt;
attr PV_Anlage_1_API reading0203JSON hostname&lt;br /&gt;
attr PV_Anlage_1_API reading0203Name info_hostname&lt;br /&gt;
attr PV_Anlage_1_API reading2001JSON 01_processdata_01_value&lt;br /&gt;
attr PV_Anlage_1_API reading2001Name Statistic_Autarky_Day&lt;br /&gt;
attr PV_Anlage_1_API reading2002JSON 01_processdata_02_value&lt;br /&gt;
attr PV_Anlage_1_API reading2002Name Statistic_Autarky_Month&lt;br /&gt;
attr PV_Anlage_1_API reading2003JSON 01_processdata_03_value&lt;br /&gt;
attr PV_Anlage_1_API reading2003Name Statistic_Autarky_Total&lt;br /&gt;
attr PV_Anlage_1_API reading2004JSON 01_processdata_04_value&lt;br /&gt;
attr PV_Anlage_1_API reading2004Name Statistic_Autarky_Year&lt;br /&gt;
attr PV_Anlage_1_API reading2011JSON 01_processdata_05_value&lt;br /&gt;
attr PV_Anlage_1_API reading2011Name Statistic_CO2Saving_Day&lt;br /&gt;
attr PV_Anlage_1_API reading2012JSON 01_processdata_06_value&lt;br /&gt;
attr PV_Anlage_1_API reading2012Name Statistic_CO2Saving_Month&lt;br /&gt;
attr PV_Anlage_1_API reading2013JSON 01_processdata_08_value&lt;br /&gt;
attr PV_Anlage_1_API reading2013Name Statistic_CO2Saving_Year&lt;br /&gt;
attr PV_Anlage_1_API reading2021JSON 01_processdata_09_value&lt;br /&gt;
attr PV_Anlage_1_API reading2021Name Statistic_EnergyHome_Day&lt;br /&gt;
attr PV_Anlage_1_API reading2022JSON 01_processdata_10_value&lt;br /&gt;
attr PV_Anlage_1_API reading2022Name Statistic_EnergyHome_Month&lt;br /&gt;
attr PV_Anlage_1_API reading2023JSON 01_processdata_11_value&lt;br /&gt;
attr PV_Anlage_1_API reading2023Name Statistic_EnergyHome_Total&lt;br /&gt;
attr PV_Anlage_1_API reading2024JSON 01_processdata_12_value&lt;br /&gt;
attr PV_Anlage_1_API reading2024Name Statistic_EnergyHome_Year&lt;br /&gt;
attr PV_Anlage_1_API reading2031JSON 01_processdata_13_value&lt;br /&gt;
attr PV_Anlage_1_API reading2031Name Statistic_EnergyHomeBat_Day&lt;br /&gt;
attr PV_Anlage_1_API reading2032JSON 01_processdata_14_value&lt;br /&gt;
attr PV_Anlage_1_API reading2032Name Statistic_EnergyHomeBat_Month&lt;br /&gt;
attr PV_Anlage_1_API reading2033JSON 01_processdata_15_value&lt;br /&gt;
attr PV_Anlage_1_API reading2033Name Statistic_EnergyHomeBat_Total&lt;br /&gt;
attr PV_Anlage_1_API reading2034JSON 01_processdata_16_value&lt;br /&gt;
attr PV_Anlage_1_API reading2034Name Statistic_EnergyHomeBat_Year&lt;br /&gt;
attr PV_Anlage_1_API reading2041JSON 01_processdata_17_value&lt;br /&gt;
attr PV_Anlage_1_API reading2041Name Statistic_EnergyHomeGrid_Day&lt;br /&gt;
attr PV_Anlage_1_API reading2042JSON 01_processdata_18_value&lt;br /&gt;
attr PV_Anlage_1_API reading2042Name Statistic_EnergyHomeGrid_Month&lt;br /&gt;
attr PV_Anlage_1_API reading2043JSON 01_processdata_19_value&lt;br /&gt;
attr PV_Anlage_1_API reading2043Name Statistic_EnergyHomeGrid_Total&lt;br /&gt;
attr PV_Anlage_1_API reading2044JSON 01_processdata_20_value&lt;br /&gt;
attr PV_Anlage_1_API reading2044Name Statistic_EnergyHomeGrid_Year&lt;br /&gt;
attr PV_Anlage_1_API reading2051JSON 01_processdata_21_value&lt;br /&gt;
attr PV_Anlage_1_API reading2051Name Statistic_EnergyHomePv_Day&lt;br /&gt;
attr PV_Anlage_1_API reading2052JSON 01_processdata_22_value&lt;br /&gt;
attr PV_Anlage_1_API reading2052Name Statistic_EnergyHomePv_Month&lt;br /&gt;
attr PV_Anlage_1_API reading2053JSON 01_processdata_23_value&lt;br /&gt;
attr PV_Anlage_1_API reading2053Name Statistic_EnergyHomePv_Total&lt;br /&gt;
attr PV_Anlage_1_API reading2054JSON 01_processdata_24_value&lt;br /&gt;
attr PV_Anlage_1_API reading2054Name Statistic_EnergyHomePv_Year&lt;br /&gt;
attr PV_Anlage_1_API reading2061JSON 01_processdata_25_value&lt;br /&gt;
attr PV_Anlage_1_API reading2061Name Statistic_OwnConsumptionRate_Day&lt;br /&gt;
attr PV_Anlage_1_API reading2062JSON 01_processdata_26_value&lt;br /&gt;
attr PV_Anlage_1_API reading2062Name Statistic_OwnConsumptionRate_Month&lt;br /&gt;
attr PV_Anlage_1_API reading2063JSON 01_processdata_27_value&lt;br /&gt;
attr PV_Anlage_1_API reading2063Name Statistic_OwnConsumptionRate_Total&lt;br /&gt;
attr PV_Anlage_1_API reading2064JSON 01_processdata_28_value&lt;br /&gt;
attr PV_Anlage_1_API reading2064Name Statistic_OwnConsumptionRate_Year&lt;br /&gt;
attr PV_Anlage_1_API reading2071JSON 01_processdata_29_value&lt;br /&gt;
attr PV_Anlage_1_API reading2071Name Statistic_Yield_Day&lt;br /&gt;
attr PV_Anlage_1_API reading2072JSON 01_processdata_30_value&lt;br /&gt;
attr PV_Anlage_1_API reading2072Name Statistic_Yield_Month&lt;br /&gt;
attr PV_Anlage_1_API reading2073JSON 01_processdata_31_value&lt;br /&gt;
attr PV_Anlage_1_API reading2073Name Statistic_Yield_Total&lt;br /&gt;
attr PV_Anlage_1_API reading2074JSON 01_processdata_32_value&lt;br /&gt;
attr PV_Anlage_1_API reading2074Name Statistic_Yield_Year&lt;br /&gt;
attr PV_Anlage_1_API replacement01Mode expression&lt;br /&gt;
attr PV_Anlage_1_API replacement01Regex %IP-Address_Plenticore%&lt;br /&gt;
attr PV_Anlage_1_API replacement01Value {ReadingsVal(&amp;quot;PV_Anlage_1_config&amp;quot;,&amp;quot;IP-Address_Plenticore&amp;quot;,&amp;quot;&amp;quot;)}&lt;br /&gt;
attr PV_Anlage_1_API replacement02Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement02Regex %auth_transactionId%&lt;br /&gt;
attr PV_Anlage_1_API replacement02Value auth_transactionId&lt;br /&gt;
attr PV_Anlage_1_API replacement03Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement03Regex %auth_proof%&lt;br /&gt;
attr PV_Anlage_1_API replacement03Value auth_proof&lt;br /&gt;
attr PV_Anlage_1_API replacement04Mode expression&lt;br /&gt;
attr PV_Anlage_1_API replacement04Regex %randomString64%&lt;br /&gt;
attr PV_Anlage_1_API replacement04Value {my $NAME = &amp;quot;PV_Anlage_1_API&amp;quot; ;;;;fhem(&amp;quot;deletereading &amp;quot;.$NAME.&amp;quot; message&amp;quot;);;;;fhem(&amp;quot;deletereading &amp;quot;.$NAME.&amp;quot; auth.*&amp;quot;);;;;my @chars=(&#039;a&#039;..&#039;z&#039;,&#039;A&#039;..&#039;Z&#039;,&#039;0&#039;..&#039;9&#039;);; my $r;; foreach(1..16) {$r.=$chars[rand @chars];;};; fhem(&amp;quot;setreading &amp;quot;.$NAME.&amp;quot; auth_randomString64 &amp;quot;.$r);; $r;;}&lt;br /&gt;
attr PV_Anlage_1_API replacement05Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement05Regex %auth_randomString64%&lt;br /&gt;
attr PV_Anlage_1_API replacement05Value auth_randomString64&lt;br /&gt;
attr PV_Anlage_1_API replacement06Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement06Regex %auth_token%&lt;br /&gt;
attr PV_Anlage_1_API replacement06Value auth_token&lt;br /&gt;
attr PV_Anlage_1_API replacement07Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement07Regex %auth_signature%&lt;br /&gt;
attr PV_Anlage_1_API replacement07Value auth_signature&lt;br /&gt;
attr PV_Anlage_1_API replacement08Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement08Regex %auth_authtag%&lt;br /&gt;
attr PV_Anlage_1_API replacement08Value auth_authtag&lt;br /&gt;
attr PV_Anlage_1_API replacement09Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement09Regex %auth_payload%&lt;br /&gt;
attr PV_Anlage_1_API replacement09Value auth_payload&lt;br /&gt;
attr PV_Anlage_1_API replacement10Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement10Regex %auth_iv%&lt;br /&gt;
attr PV_Anlage_1_API replacement10Value auth_iv&lt;br /&gt;
attr PV_Anlage_1_API replacement11Mode reading&lt;br /&gt;
attr PV_Anlage_1_API replacement11Regex %auth_sessionId%&lt;br /&gt;
attr PV_Anlage_1_API replacement11Value auth_sessionId&lt;br /&gt;
attr PV_Anlage_1_API room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_Anlage_1_API showBody 1&lt;br /&gt;
attr PV_Anlage_1_API showError 1&lt;br /&gt;
attr PV_Anlage_1_API sid01Data {&amp;quot;nonce&amp;quot;: &amp;quot;%randomString64%&amp;quot;,&amp;quot;username&amp;quot;: &amp;quot;user&amp;quot;}&lt;br /&gt;
attr PV_Anlage_1_API sid01ParseResponse 1&lt;br /&gt;
attr PV_Anlage_1_API sid01URL http://%IP-Address_Plenticore%/api/v1/auth/start&lt;br /&gt;
attr PV_Anlage_1_API sidHeader01 Accept-Encoding: gzip,deflate&lt;br /&gt;
attr PV_Anlage_1_API sidHeader02 Content-type: application/json, Accept: application/json, Connection: keep-alive&lt;br /&gt;
attr PV_Anlage_1_API sortby 02&lt;br /&gt;
attr PV_Anlage_1_API timeout 5&lt;br /&gt;
attr PV_Anlage_1_API userReadings auth_Step1_Message:auth_nonce.* {system(&amp;quot;/usr/bin/python3 /opt/fhem/python/bin/plenticore_auth_finish.py &amp;quot;.ReadingsVal(&amp;quot;PV_Anlage_1_config&amp;quot;,&amp;quot;IP-Address_FHEM&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;amp;&amp;quot;);;;; &amp;quot;Prepare auth_finish started with auth_nonce &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;)},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step2_Message:auth_proof.* { fhem(&amp;quot;get &amp;quot;.$NAME.&amp;quot; 02_/auth/finish&amp;quot;) ;;;; &amp;quot;HTTP Request 02_/auth/finish with auth_proof &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_proof&amp;quot;,&amp;quot;&amp;quot;)},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step3_Message:auth_token.* {system(&amp;quot;/usr/bin/python3 /opt/fhem/python/bin/plenticore_auth_session.py &amp;quot;.ReadingsVal(&amp;quot;PV_Anlage_1_config&amp;quot;,&amp;quot;IP-Address_FHEM&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_randomString64&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_nonce&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_salt&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_rounds&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;&amp;quot;).&amp;quot; &amp;amp;&amp;quot;);;;; &amp;quot;Prepare auth_session started with auth_token &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_token&amp;quot;,&amp;quot;&amp;quot;)},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step4_Message:auth_payload.* { fhem(&amp;quot;get &amp;quot;.$NAME.&amp;quot; 03_/auth/create_session&amp;quot;) ;;;; &amp;quot;HTTP Request 03_/auth/create_session with auth_authtag &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_authtag&amp;quot;,&amp;quot;&amp;quot;)},\&lt;br /&gt;
\&lt;br /&gt;
auth_Step5_Message:auth_sessionId.* { fhem(&amp;quot;get &amp;quot;.$NAME.&amp;quot; 04_/auth/me&amp;quot;) ;;;; &amp;quot;HTTP Request 04_/auth/me with auth_sessionId &amp;quot;.ReadingsVal(&amp;quot;$NAME&amp;quot;,&amp;quot;auth_sessionId&amp;quot;,&amp;quot;&amp;quot;)}&lt;br /&gt;
attr PV_Anlage_1_API verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Kostal Smart Energy Manager (KSEM) (Modbus/TCP) ===&lt;br /&gt;
Diese Einbindung ist nicht zwingend notwendig, jedoch weil es möglich ist hier beschrieben.&lt;br /&gt;
Das Gerät ist hier mit &amp;quot;disable 1&amp;quot; konfiguriert, um es zu verwenden muss das Attribut auf 0 gesetzt oder einfach gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Auch hier ist ein Interval von 60 Sekunden gesetzt worden. Das Logging ist noch komplett deaktiviert, weshalb man seine Werte noch selber definieren muss.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition des KSEM ====&lt;br /&gt;
Zun Thema KSEM bestand direkter Kontakt mit dem Kostal Service. Der KSEM ermittelt nicht alle Werte, welche in der SunSpec spezifiziert sind. Alle nicht unterstützen Werte sind in den Registern mit 0x8000 gekennzeichnet. Für die nicht unterstützten Zählerstände wird 0x800000000 ausgegeben.&lt;br /&gt;
Der Summenstrom M_AC_Current (sum of active phases) kann aber durch den Endanwender selber aus der Summe der Einzelwerte (Phase A AC current, Phase B AC current Phase C AC current) berechnet werden. Die einzelnen Spannungen zwischen den Phasen können nicht gemessen werden und werden deshalb nicht ausgegeben.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_KSEM ModbusAttr 1 60 &amp;lt;IP-Address_KSEM&amp;gt;:502 TCP&lt;br /&gt;
attr PV_KSEM DbLogExclude .*&lt;br /&gt;
attr PV_KSEM alias PV_Energy_Manager&lt;br /&gt;
attr PV_KSEM dev-h-defPoll 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Current-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Current_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Current-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Current-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Current-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Freq-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Freq_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Freq-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Freq-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Freq-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_PF-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_PF_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_PF-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_PF-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_PF-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Power-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Power_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Power-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Power-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Power-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VA-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VA_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VA-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VA-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VA-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VAR-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_VAR_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VAR-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VAR-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_VAR-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Voltage-expr $val * (10 ** ReadingsNum(&amp;quot;$name&amp;quot; ,&amp;quot;M_AC_Voltage_SF&amp;quot;,0))&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Voltage-format %.2f&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Voltage-len 1&lt;br /&gt;
attr PV_KSEM dev-type-INT16_Voltage-unpack s&amp;gt;&lt;br /&gt;
attr PV_KSEM dev-type-STR32-expr $val =~ s/[\00]+//gr&lt;br /&gt;
attr PV_KSEM dev-type-STR32-format %s&lt;br /&gt;
attr PV_KSEM dev-type-STR32-len 16&lt;br /&gt;
attr PV_KSEM dev-type-STR32-unpack a*&lt;br /&gt;
attr PV_KSEM dev-type-UINT16-format %s&lt;br /&gt;
attr PV_KSEM dev-type-UINT16-len 1&lt;br /&gt;
attr PV_KSEM dev-type-UINT32-format %s&lt;br /&gt;
attr PV_KSEM dev-type-UINT32-len 2&lt;br /&gt;
attr PV_KSEM dev-type-UINT64-expr $val/10000&lt;br /&gt;
attr PV_KSEM dev-type-UINT64-format %s&lt;br /&gt;
attr PV_KSEM dev-type-UINT64-len 4&lt;br /&gt;
attr PV_KSEM dev-type-UINT64-unpack Q&amp;gt;&lt;br /&gt;
attr PV_KSEM disable 1&lt;br /&gt;
attr PV_KSEM group PV Eigenverbrauch&lt;br /&gt;
attr PV_KSEM icon measure_power&lt;br /&gt;
attr PV_KSEM obj-h40072-reading M_AC_Current_A&lt;br /&gt;
attr PV_KSEM obj-h40072-type INT16_Current&lt;br /&gt;
attr PV_KSEM obj-h40073-reading M_AC_Current_B&lt;br /&gt;
attr PV_KSEM obj-h40073-type INT16_Current&lt;br /&gt;
attr PV_KSEM obj-h40074-reading M_AC_Current_C&lt;br /&gt;
attr PV_KSEM obj-h40074-type INT16_Current&lt;br /&gt;
attr PV_KSEM obj-h40075-reading M_AC_Current_SF&lt;br /&gt;
attr PV_KSEM obj-h40075-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40077-reading M_AC_Voltage_AN&lt;br /&gt;
attr PV_KSEM obj-h40077-type INT16_Voltage&lt;br /&gt;
attr PV_KSEM obj-h40078-reading M_AC_Voltage_BN&lt;br /&gt;
attr PV_KSEM obj-h40078-type INT16_Voltage&lt;br /&gt;
attr PV_KSEM obj-h40079-reading M_AC_Voltage_CN&lt;br /&gt;
attr PV_KSEM obj-h40079-type INT16_Voltage&lt;br /&gt;
attr PV_KSEM obj-h40084-reading M_AC_Voltage_SF&lt;br /&gt;
attr PV_KSEM obj-h40084-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40085-reading M_AC_Freq&lt;br /&gt;
attr PV_KSEM obj-h40085-type INT16_Freq&lt;br /&gt;
attr PV_KSEM obj-h40086-reading M_AC_Freq_SF&lt;br /&gt;
attr PV_KSEM obj-h40086-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40087-reading M_AC_Power&lt;br /&gt;
attr PV_KSEM obj-h40087-type INT16_Power&lt;br /&gt;
attr PV_KSEM obj-h40088-reading M_AC_Power_A&lt;br /&gt;
attr PV_KSEM obj-h40088-type INT16_Power&lt;br /&gt;
attr PV_KSEM obj-h40089-reading M_AC_Power_B&lt;br /&gt;
attr PV_KSEM obj-h40089-type INT16_Power&lt;br /&gt;
attr PV_KSEM obj-h40090-reading M_AC_Power_C&lt;br /&gt;
attr PV_KSEM obj-h40090-type INT16_Power&lt;br /&gt;
attr PV_KSEM obj-h40091-reading M_AC_Power_SF&lt;br /&gt;
attr PV_KSEM obj-h40091-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40092-reading M_AC_VA&lt;br /&gt;
attr PV_KSEM obj-h40092-type INT16_VA&lt;br /&gt;
attr PV_KSEM obj-h40093-reading M_AC_VA_A&lt;br /&gt;
attr PV_KSEM obj-h40093-type INT16_VA&lt;br /&gt;
attr PV_KSEM obj-h40094-reading M_AC_VA_B&lt;br /&gt;
attr PV_KSEM obj-h40094-type INT16_VA&lt;br /&gt;
attr PV_KSEM obj-h40095-reading M_AC_VA_C&lt;br /&gt;
attr PV_KSEM obj-h40095-type INT16_VA&lt;br /&gt;
attr PV_KSEM obj-h40096-reading M_AC_VA_SF&lt;br /&gt;
attr PV_KSEM obj-h40096-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40097-reading M_AC_VAR&lt;br /&gt;
attr PV_KSEM obj-h40097-type INT16_VAR&lt;br /&gt;
attr PV_KSEM obj-h40098-reading M_AC_VAR_A&lt;br /&gt;
attr PV_KSEM obj-h40098-type INT16_VAR&lt;br /&gt;
attr PV_KSEM obj-h40099-reading M_AC_VAR_B&lt;br /&gt;
attr PV_KSEM obj-h40099-type INT16_VAR&lt;br /&gt;
attr PV_KSEM obj-h40100-reading M_AC_VAR_C&lt;br /&gt;
attr PV_KSEM obj-h40100-type INT16_VAR&lt;br /&gt;
attr PV_KSEM obj-h40101-reading M_AC_VAR_SF&lt;br /&gt;
attr PV_KSEM obj-h40101-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40102-reading M_AC_PF&lt;br /&gt;
attr PV_KSEM obj-h40102-type INT16_PF&lt;br /&gt;
attr PV_KSEM obj-h40103-reading M_AC_PF_A&lt;br /&gt;
attr PV_KSEM obj-h40103-type INT16_PF&lt;br /&gt;
attr PV_KSEM obj-h40104-reading M_AC_PF_B&lt;br /&gt;
attr PV_KSEM obj-h40104-type INT16_PF&lt;br /&gt;
attr PV_KSEM obj-h40105-reading M_AC_PF_C&lt;br /&gt;
attr PV_KSEM obj-h40105-type INT16_PF&lt;br /&gt;
attr PV_KSEM obj-h40106-reading M_AC_PF_SF&lt;br /&gt;
attr PV_KSEM obj-h40106-type INT16&lt;br /&gt;
attr PV_KSEM obj-h40108-reading M_Exported&lt;br /&gt;
attr PV_KSEM obj-h40108-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40110-reading M_Exported_A&lt;br /&gt;
attr PV_KSEM obj-h40110-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40112-reading M_Exported_B&lt;br /&gt;
attr PV_KSEM obj-h40112-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40114-reading M_Exported_C&lt;br /&gt;
attr PV_KSEM obj-h40114-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40116-reading M_Imported&lt;br /&gt;
attr PV_KSEM obj-h40116-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40118-reading M_Imported_A&lt;br /&gt;
attr PV_KSEM obj-h40118-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40120-reading M_Imported_B&lt;br /&gt;
attr PV_KSEM obj-h40120-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40122-reading M_Imported_C&lt;br /&gt;
attr PV_KSEM obj-h40122-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40125-reading M_Exported_VA&lt;br /&gt;
attr PV_KSEM obj-h40125-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40127-reading M_Exported_VA_A&lt;br /&gt;
attr PV_KSEM obj-h40127-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40129-reading M_Exported_VA_B&lt;br /&gt;
attr PV_KSEM obj-h40129-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40131-reading M_Exported_VA_C&lt;br /&gt;
attr PV_KSEM obj-h40131-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40133-reading M_Imported_VA&lt;br /&gt;
attr PV_KSEM obj-h40133-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40135-reading M_Imported_VA_A&lt;br /&gt;
attr PV_KSEM obj-h40135-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40137-reading M_Imported_VA_B&lt;br /&gt;
attr PV_KSEM obj-h40137-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h40139-reading M_Imported_VA_C&lt;br /&gt;
attr PV_KSEM obj-h40139-type UINT32&lt;br /&gt;
attr PV_KSEM obj-h512-reading Active_energy+&lt;br /&gt;
attr PV_KSEM obj-h512-type UINT64&lt;br /&gt;
attr PV_KSEM obj-h516-reading Active_energy-&lt;br /&gt;
attr PV_KSEM obj-h516-type UINT64&lt;br /&gt;
attr PV_KSEM obj-h8192-reading ManufacturerID&lt;br /&gt;
attr PV_KSEM obj-h8192-type UINT16&lt;br /&gt;
attr PV_KSEM obj-h8193-reading ProductID&lt;br /&gt;
attr PV_KSEM obj-h8193-type UINT16&lt;br /&gt;
attr PV_KSEM obj-h8194-reading ProductVersion&lt;br /&gt;
attr PV_KSEM obj-h8194-type UINT16&lt;br /&gt;
attr PV_KSEM obj-h8195-reading FirmwareVersion&lt;br /&gt;
attr PV_KSEM obj-h8195-type UINT16&lt;br /&gt;
attr PV_KSEM obj-h8196-reading VendorName&lt;br /&gt;
attr PV_KSEM obj-h8196-type STR32&lt;br /&gt;
attr PV_KSEM obj-h8212-reading Productname&lt;br /&gt;
attr PV_KSEM obj-h8212-type STR32&lt;br /&gt;
attr PV_KSEM obj-h8228-reading SerialNumber&lt;br /&gt;
attr PV_KSEM obj-h8228-type STR32&lt;br /&gt;
attr PV_KSEM obj-h8244-reading MeasuringInterval&lt;br /&gt;
attr PV_KSEM obj-h8244-type UINT16&lt;br /&gt;
attr PV_KSEM room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr PV_KSEM sortby 03&lt;br /&gt;
attr PV_KSEM userReadings M_AC_Current:M_AC_Current_.* { ReadingsVal($NAME,&amp;quot;M_AC_Current_A&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_B&amp;quot;,0) + ReadingsVal($NAME,&amp;quot;M_AC_Current_C&amp;quot;,0) }&lt;br /&gt;
attr PV_KSEM verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== BYD Speicher (über Python Skript) ===&lt;br /&gt;
Diese Einbindung ist nicht zwingend notwendig.&lt;br /&gt;
Ein Ziel ist es das Python Skript später zu entfernen und eine direkten HTTPMOD Abfrage zu implementieren.&lt;br /&gt;
==== byd_status.py ====&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ cat byd_status.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Copyright: Kilian Knoll, 10.3.2019&lt;br /&gt;
#&lt;br /&gt;
# Utility to parse rundata values of BYD HV BOX&lt;br /&gt;
# Version 1.0&lt;br /&gt;
#  &lt;br /&gt;
#  This program is free software: you can redistribute it and/or modify&lt;br /&gt;
#  it under the terms of the GNU General Public License as published by&lt;br /&gt;
#  the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
#  (at your option) any later version.&lt;br /&gt;
#&lt;br /&gt;
#  This program is distributed in the hope that it will be useful,&lt;br /&gt;
#  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
#  GNU General Public License for more details.&lt;br /&gt;
#&lt;br /&gt;
#  You should have received a copy of the GNU General Public License&lt;br /&gt;
#  along with this program.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#  Please note that any incorrect or careless usage of this module as well as errors in the implementation can damage your BYD box!&lt;br /&gt;
#  Therefore, the author does not provide any guarantee or warranty concerning to correctness, functionality or performance and does not accept any liability for damage caused by this module, examples or mentioned information.&lt;br /&gt;
#  Thus, use it at your own risk!&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#  Purpose: &lt;br /&gt;
#     Query Rundata values from BYD box via local network connection &lt;br /&gt;
#     Used with BYD HV 6.4&lt;br /&gt;
#&lt;br /&gt;
#     Returnvalue: 0    (Everything all right)&lt;br /&gt;
#     Returnvalue: -1   (Crap happened)&lt;br /&gt;
#     BYDdata:          (Empty list in case Returnvalue =-1)&lt;br /&gt;
#     BYDdata:          (Full list of key-value pairs in case Returnvalue = 0)&lt;br /&gt;
#&lt;br /&gt;
# Tested with&lt;br /&gt;
#   BYD HV 6.4,&lt;br /&gt;
#   Firmware verison V3.012 R&lt;br /&gt;
#   python 3.6&lt;br /&gt;
#&lt;br /&gt;
# Changes:&lt;br /&gt;
# 2020.07.30 added fhem connectivity &lt;br /&gt;
#            added sys for argument parsing; BYDboxIP and FHEM Web Interface are read from commandline&lt;br /&gt;
#            password and username is read from file&lt;br /&gt;
&lt;br /&gt;
import fhem&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
BYDboxIP = sys.argv[1]&lt;br /&gt;
web      = sys.argv[2]&lt;br /&gt;
&lt;br /&gt;
import requests&lt;br /&gt;
import time &lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
from pprint import pprint&lt;br /&gt;
from bs4 import BeautifulSoup &lt;br /&gt;
from requests.auth import HTTPBasicAuth &lt;br /&gt;
import logging&lt;br /&gt;
&lt;br /&gt;
#from loggerdate import loggerdate&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def getvaluefromsubstring (inputvalue):&lt;br /&gt;
    # The input we pass looks like this:&lt;br /&gt;
    #&amp;lt;input readonly=&amp;quot;readonly&amp;quot; type=&amp;quot;text&amp;quot; value=&amp;quot;5186&amp;quot;/&amp;gt;&lt;br /&gt;
    #Goal is to return value 5186 as outputvalue&lt;br /&gt;
    #Not sure if BeautifulSoup could do more / better... &lt;br /&gt;
    output_array=  str(inputvalue)&lt;br /&gt;
    A,B,C,outputvalue=  output_array.split(&#039;=&#039;)&lt;br /&gt;
    outputvalue, A= outputvalue.split(&#039;/&#039;)&lt;br /&gt;
    A,outputvalue,B = outputvalue.split(&#039;&amp;quot;&#039;)&lt;br /&gt;
    if (&#039;%&#039; in outputvalue):&lt;br /&gt;
        outputvalue, A = outputvalue.split(&#039;%&#039;)&lt;br /&gt;
    outputvalue = float(outputvalue)&lt;br /&gt;
    return outputvalue&lt;br /&gt;
&lt;br /&gt;
def readbyd():&lt;br /&gt;
&lt;br /&gt;
    #Please adjust the parameters below as appropriate for your environment:&lt;br /&gt;
&lt;br /&gt;
    # username and password are read from pwd_byd.json file ; BYDboxIP is parsed from sys commandline&lt;br /&gt;
    #print (&amp;quot;Start reading Password file for BYD access....&amp;quot;)&lt;br /&gt;
    try:&lt;br /&gt;
        with open(&#039;/opt/fhem/python/pwd_byd.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
            credentials=json.load(f)&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
        print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
    #No configurable parameters beyond this point        &lt;br /&gt;
    &lt;br /&gt;
    mySession = requests.Session()&lt;br /&gt;
    try:&lt;br /&gt;
        BYDdata={}&lt;br /&gt;
        #The two stupid lines below took me almost a day...&lt;br /&gt;
        #You can access other pages on the BYD WEB-Page - calling other asp scripts&lt;br /&gt;
        url=&#039;http://&#039;+BYDboxIP+&#039;/asp/RunData.asp&#039;&lt;br /&gt;
        r4 = mySession.get(url, auth=HTTPBasicAuth(credentials[&amp;quot;username&amp;quot;],credentials[&amp;quot;password&amp;quot;]))&lt;br /&gt;
        if (r4.status_code == 200):&lt;br /&gt;
            page = r4.text &lt;br /&gt;
            soup = BeautifulSoup(page, &#039;html.parser&#039;)&lt;br /&gt;
            soup_ele = soup.body.form.table                                    #This gets us the RunData Table and Array Num 1 values - using this approach&lt;br /&gt;
            soup_reduced = soup_ele.find_all(&#039;input&#039;,attrs={&amp;quot;type&amp;quot;: &amp;quot;text&amp;quot;} )  #Using this option now since BYD introduced some glitches with Firmware 3.012R on their html code.. &lt;br /&gt;
            # It now contains a list of the following kind&lt;br /&gt;
            #&amp;lt;input readonly=&amp;quot;readonly&amp;quot; type=&amp;quot;text&amp;quot; value=&amp;quot;19.300&amp;quot;/&amp;gt;&lt;br /&gt;
            #print (soup_reduced)&lt;br /&gt;
            #print (&amp;quot;ERSTES ELE&amp;quot;, soup_reduced[1]) &lt;br /&gt;
            Keyvalue=[]&lt;br /&gt;
            for elems in soup_reduced:&lt;br /&gt;
                elems=str(elems)&lt;br /&gt;
                myarray= elems.split(&#039;=&#039;)&lt;br /&gt;
                CurValue=myarray[3].split(&#039;&amp;quot;&#039;)&lt;br /&gt;
                Keyvalue.append(CurValue[1])&lt;br /&gt;
&lt;br /&gt;
            BYDdata[&amp;quot;arrayvoltage&amp;quot;]= float(Keyvalue[0])&lt;br /&gt;
            BYDdata[&amp;quot;packvoltage&amp;quot;] = float(Keyvalue[1])&lt;br /&gt;
            BYDdata[&amp;quot;current&amp;quot;] = float(Keyvalue[2])&lt;br /&gt;
            BYDdata[&amp;quot;soc&amp;quot;] = (Keyvalue[3])&lt;br /&gt;
            BYDdata[&amp;quot;sysTemp&amp;quot;] = Keyvalue[4]         &lt;br /&gt;
            BYDdata[&amp;quot;maxcellvol&amp;quot;] = float(Keyvalue[5])&lt;br /&gt;
            BYDdata[&amp;quot;mincellvol&amp;quot;] = float(Keyvalue[6])       &lt;br /&gt;
            BYDdata[&amp;quot;maxcelltemp&amp;quot;] = float(Keyvalue[7])&lt;br /&gt;
            BYDdata[&amp;quot;mincelltemp&amp;quot;] = float(Keyvalue[8])&lt;br /&gt;
            BYDdata[&amp;quot;maxvolpos&amp;quot;] = int(Keyvalue[9])&lt;br /&gt;
            BYDdata[&amp;quot;minvolpos&amp;quot;] = Keyvalue[10]&lt;br /&gt;
            BYDdata[&amp;quot;maxtemppos&amp;quot;] = Keyvalue[11]&lt;br /&gt;
            BYDdata[&amp;quot;mintemppos&amp;quot;] = Keyvalue[12]&lt;br /&gt;
            BYDdata[&amp;quot;power&amp;quot;] = Keyvalue[13]            &lt;br /&gt;
            &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
            # Oh well - with Firmware 3.012R, these values have disappeared from the BYD web pages...&lt;br /&gt;
            BYDdata[&amp;quot;soc&amp;quot;] = Keyvalue[3]&lt;br /&gt;
            BYDdata[&amp;quot;socwh&amp;quot;] = Keyvalue[4]&lt;br /&gt;
            BYDdata[&amp;quot;socah&amp;quot;] = Keyvalue[5]   &lt;br /&gt;
            BYDdata[&amp;quot;soh&amp;quot;] = Keyvalue[6]                 &lt;br /&gt;
            &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
            Error_Connecting = 0&lt;br /&gt;
&lt;br /&gt;
        else:&lt;br /&gt;
            print (&amp;quot;Not sure if we are able to connect with the given username &amp;amp; password - error code is:&amp;quot;, r4.status_code)&lt;br /&gt;
            print (&amp;quot;Header information passed is :&amp;quot;, r4.headers)&lt;br /&gt;
            Error_Connecting = r4.status_code&lt;br /&gt;
    &lt;br /&gt;
        url=&#039;http://&#039;+BYDboxIP+&#039;/asp/StatisticInformation.asp&#039;&lt;br /&gt;
        r2 = mySession.get(url, auth=HTTPBasicAuth(credentials[&amp;quot;username&amp;quot;],credentials[&amp;quot;password&amp;quot;]))&lt;br /&gt;
        if ((r2.status_code == 200) and (Error_Connecting == 0)):&lt;br /&gt;
            page = r2.text &lt;br /&gt;
            soup = BeautifulSoup(page, &#039;html.parser&#039;)&lt;br /&gt;
            soup_ele = soup.body.table   &lt;br /&gt;
            #print (soup_ele)&lt;br /&gt;
            #print (&amp;quot;--------------------------------------------------------&amp;quot;)&lt;br /&gt;
            #&amp;lt;input readonly=&amp;quot;readonly&amp;quot; type=&amp;quot;text&amp;quot; value=&amp;quot;5186&amp;quot;/&amp;gt;&lt;br /&gt;
            soup_reduced = soup_ele.find_all(&#039;input&#039;)&lt;br /&gt;
            #print (soup_reduced)&lt;br /&gt;
            #print (&amp;quot;soup_ele&amp;quot;, soup_ele)&lt;br /&gt;
            i = 0&lt;br /&gt;
            a= len(soup_ele.contents)&lt;br /&gt;
            total_charge_energy = soup_ele.find(&amp;quot;td&amp;quot;, text=&amp;quot;Total Charge Energy:&amp;quot;).find_next_sibling(&amp;quot;td&amp;quot;).text&lt;br /&gt;
            total_charge_energy,b = (total_charge_energy.split())&lt;br /&gt;
            total_charge_energy = float(total_charge_energy)&lt;br /&gt;
            #print (&amp;quot;Total Charge Energy :&amp;quot;, total_charge_energy)&lt;br /&gt;
            BYDdata[&amp;quot;Total_Charge_Energy&amp;quot;]= total_charge_energy&lt;br /&gt;
            &lt;br /&gt;
            total_discharge_energy = soup_ele.find(&amp;quot;td&amp;quot;, text=&amp;quot;Total Discharge Energy:&amp;quot;).find_next_sibling(&amp;quot;td&amp;quot;).text&lt;br /&gt;
            total_discharge_energy,b = (total_discharge_energy.split())&lt;br /&gt;
            total_discharge_energy = float(total_discharge_energy)&lt;br /&gt;
            #print (&amp;quot;Total Discharge Energy :&amp;quot;, total_discharge_energy)&lt;br /&gt;
            BYDdata[&amp;quot;Total_Discharge_Energy&amp;quot;] = total_discharge_energy&lt;br /&gt;
            &lt;br /&gt;
            total_cycle_counts = soup_ele.find(&amp;quot;td&amp;quot;, text=&amp;quot;Total Cycle Counts:&amp;quot;).find_next_sibling(&amp;quot;td&amp;quot;).text&lt;br /&gt;
            #total_cycle_counts,b = (total_cycle_counts.split())&lt;br /&gt;
            total_cycle_counts = float(total_cycle_counts)&lt;br /&gt;
            #print (&amp;quot;Total Cycle Counts :&amp;quot;, total_cycle_counts) &lt;br /&gt;
            BYDdata[&amp;quot;Total_Cycle_Counts&amp;quot;] = total_cycle_counts&lt;br /&gt;
        else:&lt;br /&gt;
            print (&amp;quot;Not sure if we are able to connect with the given username &amp;amp; password - error code is:&amp;quot;, r4.status_code)&lt;br /&gt;
            print (&amp;quot;Header information passed is :&amp;quot;, r2.headers)&lt;br /&gt;
            Error_Connecting = r2.status_code&lt;br /&gt;
            &lt;br /&gt;
    except Exception as Connecterror:&lt;br /&gt;
        print (&amp;quot;Error connecting to the BYD box :&amp;quot;, Connecterror)&lt;br /&gt;
        #logging.error(&amp;quot;%s %s %s&amp;quot;, loggerdate(), &amp;quot;,readbyd: Ran into exception querying the BYD Box : &amp;quot;, Connecterror)&lt;br /&gt;
        Error_Connecting = Connecterror&lt;br /&gt;
    if (Error_Connecting == 0):&lt;br /&gt;
        if (len(BYDdata) &amp;gt;1):                         # We have something in the list&lt;br /&gt;
&lt;br /&gt;
            Returnvalue =0&lt;br /&gt;
    else:                                               # We ran into trouble and allocate an empty list&lt;br /&gt;
        BYDdata={}&lt;br /&gt;
        print (&amp;quot;Issue getting data from BYD &amp;quot;, Error_Connecting)&lt;br /&gt;
        &lt;br /&gt;
    return (Returnvalue, BYDdata)    &lt;br /&gt;
        &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:  &lt;br /&gt;
&lt;br /&gt;
    #print (&amp;quot;Start querying BYD....&amp;quot;)&lt;br /&gt;
    try:&lt;br /&gt;
        Myreturnvalue, Mydata = readbyd();&lt;br /&gt;
        if (Myreturnvalue == 0):&lt;br /&gt;
            #print (&amp;quot;Returnvalue -should be zero if successful : &amp;quot;, Myreturnvalue)&lt;br /&gt;
            #print (&amp;quot;----------------Start Values BYD ----------------&amp;quot;)&lt;br /&gt;
            #pprint (Mydata)&lt;br /&gt;
            #print (&amp;quot;----------------End - Values from BYD ----------------&amp;quot;)	&lt;br /&gt;
            #print (&amp;quot;Specific values from array....&amp;quot;)&lt;br /&gt;
            #print (&amp;quot;BYD Total Charge Energy                 :&amp;quot;, Mydata[&#039;Total_Charge_Energy&#039;], &amp;quot;Kwh&amp;quot;)&lt;br /&gt;
            #print (&amp;quot;BYD Total Discharge Energy              :&amp;quot;, Mydata[&#039;Total_Discharge_Energy&#039;], &amp;quot;Kwh&amp;quot;)&lt;br /&gt;
            #print (&amp;quot;Calculations...&amp;quot;)&lt;br /&gt;
            #print (&amp;quot;Charging (+) / Discharging (-) Energy   :&amp;quot;, round(Mydata[&#039;packvoltage&#039;]*Mydata[&#039;current&#039;],0), &amp;quot;W&amp;quot;)&lt;br /&gt;
            #print (&amp;quot;Efficiency is                           :&amp;quot;,round(Mydata[&#039;Total_Discharge_Energy&#039;]/Mydata[&#039;Total_Charge_Energy&#039;],3))&lt;br /&gt;
            #print (Mydata)&lt;br /&gt;
&lt;br /&gt;
            message = json.dumps(Mydata)&lt;br /&gt;
&lt;br /&gt;
            #print (&amp;quot;Start reading Password file for FHEM access....&amp;quot;)&lt;br /&gt;
            try:&lt;br /&gt;
                with open(&#039;/opt/fhem/python/pwd_fhem.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
                    credentials=json.load(f)&lt;br /&gt;
            except Exception as e:&lt;br /&gt;
                print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
            #print (&amp;quot;Start login to FHEM ....&amp;quot;)&lt;br /&gt;
            fh = fhem.Fhem(web, protocol=&amp;quot;http&amp;quot;, port=8083, username=credentials[&amp;quot;username&amp;quot;], password=credentials[&amp;quot;password&amp;quot;])&lt;br /&gt;
&lt;br /&gt;
            #print (&amp;quot;Start transfer of data to FHEM ....&amp;quot;)&lt;br /&gt;
            fh.send_cmd(&amp;quot;setreading BYD_Status output &amp;quot; + message)&lt;br /&gt;
&lt;br /&gt;
        else:&lt;br /&gt;
            print (&amp;quot;Error unable to query BYD Box&amp;quot;)&lt;br /&gt;
    except Exception as ex:&lt;br /&gt;
        print (&amp;quot;Issues querying BYD Box :&amp;quot;, ex)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
====== Userreadings ======&lt;br /&gt;
Die Userreadings gehören zum Gerät BYD_Status .&lt;br /&gt;
&lt;br /&gt;
output&lt;br /&gt;
   Trigger: externes Python Skript&lt;br /&gt;
   Das Python Skript beschreibt im Gerät BYD_Status das reading output, das dort dann weiter verarbeitet wird.&lt;br /&gt;
&lt;br /&gt;
====== Passworte ======&lt;br /&gt;
Das Passwort für den BYD Speicher liegt in einer JSON Datei&lt;br /&gt;
&lt;br /&gt;
fhem@raspberrypi:~/python$ cat pwd_byd.json&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;username&amp;quot;: &amp;quot;installer&amp;quot;,&lt;br /&gt;
    &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;Steht in der BYD Dokumentation&amp;gt;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== RAW Definition BYD_Status ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod BYD_Status expandJSON BYD_Status:output:.\{.*}&lt;br /&gt;
attr BYD_Status DbLogExclude .*&lt;br /&gt;
attr BYD_Status alias BYD_Status&lt;br /&gt;
attr BYD_Status comment Das Device wird über ein Python Skript im reading output befüllt.\&lt;br /&gt;
deletereading BYD_Status [min|max|cur|array|Total|pack|power|soc|sys].*\&lt;br /&gt;
&lt;br /&gt;
attr BYD_Status group PV Eigenverbrauch&lt;br /&gt;
attr BYD_Status icon measure_battery_50&lt;br /&gt;
attr BYD_Status room Strom-&amp;gt;Photovoltaik,Strom-&amp;gt;System&lt;br /&gt;
attr BYD_Status sortby 02&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
== Timeing für die PV extra Funktionen ==&lt;br /&gt;
=== RAW Definition PV_Schedule (DOIF) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod PV_Schedule DOIF ################################################################################################################\&lt;br /&gt;
## 1 BYD Status aktualisieren\&lt;br /&gt;
##\&lt;br /&gt;
 ([+:05] and !([:00] or [:30]))\&lt;br /&gt;
   (\&lt;br /&gt;
      {system(&amp;quot;/usr/bin/python3 /opt/fhem/python/bin/byd_status.py &amp;quot;.ReadingsVal(&amp;quot;BYD_Status&amp;quot;,&amp;quot;IP-Address_BYD&amp;quot;,&amp;quot;?&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;BYD_Status&amp;quot;,&amp;quot;IP-Address_FHEM&amp;quot;,&amp;quot;?&amp;quot;).&amp;quot; &amp;amp;&amp;quot;)}\&lt;br /&gt;
   )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Plenticore Status aktualisieren\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([:57])\&lt;br /&gt;
   (\&lt;br /&gt;
    {system(&amp;quot;/usr/bin/python3 /opt/fhem/python/bin/plenticore_statistic.py &amp;quot;.ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;IP-Address_Plenticore&amp;quot;,&amp;quot;?&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;IP-Address_FHEM&amp;quot;,&amp;quot;?&amp;quot;).&amp;quot; &amp;amp;&amp;quot;)}\&lt;br /&gt;
   set Dum.Energy update\&lt;br /&gt;
\&lt;br /&gt;
   )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 DWD Prognose aktualisieren, die Daten stehen immer verzögert zur Verfügung.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([06:37] or [11:37] or [17:37] or [00:37])\&lt;br /&gt;
   (\&lt;br /&gt;
    {system(&amp;quot;/usr/bin/python3 /opt/fhem/python/bin/dwd_get_forecast.py &amp;quot;.ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;IP-Address_FHEM&amp;quot;,&amp;quot;?&amp;quot;).&amp;quot; &amp;quot;.ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Solar_Station&amp;quot;,&amp;quot;?&amp;quot;).&amp;quot; &amp;amp;&amp;quot;)}\&lt;br /&gt;
   )\&lt;br /&gt;
\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 PV Prognose vom aktuellen Tag aktualisieren\&lt;br /&gt;
##     zwischen 7 und 19 Uhr zur vollen Stunde\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([07:00-19:00] and [:00])\&lt;br /&gt;
   (\&lt;br /&gt;
    {Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_delete_PV_Forecast&amp;quot;,&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;ESW&amp;quot;,&amp;quot;DWD_Prognose&amp;quot;,&amp;quot;ProPlanta&amp;quot;,0)}\&lt;br /&gt;
   )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 PV Prognose für den nächsten Tag aktualisieren\&lt;br /&gt;
## \&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([09:11])\&lt;br /&gt;
   (\&lt;br /&gt;
    {Solar_forecast(&amp;quot;LogDB&amp;quot;,&amp;quot;LogDBRep_delete_PV_Forecast&amp;quot;,&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Solar_Calculation_fc&amp;quot;,&amp;quot;ESW&amp;quot;,&amp;quot;DWD_Prognose&amp;quot;,&amp;quot;ProPlanta&amp;quot;,1)}\&lt;br /&gt;
   )\&lt;br /&gt;
&lt;br /&gt;
attr PV_Schedule DbLogExclude .*&lt;br /&gt;
attr PV_Schedule alias PV_Schedule&lt;br /&gt;
attr PV_Schedule cmdState BYD Status|Plenticore Status&lt;br /&gt;
attr PV_Schedule do always&lt;br /&gt;
attr PV_Schedule room Strom-&amp;gt;System&lt;br /&gt;
attr PV_Schedule sortby 11&lt;br /&gt;
attr PV_Schedule wait 0:0:0:10:0:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Energie Bilanz ==&lt;br /&gt;
=== RAW Definition Energiebilanz ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Dum.Energy dummy&lt;br /&gt;
attr Dum.Energy DbLogExclude .*&lt;br /&gt;
attr Dum.Energy DbLogInclude Autarky.*,GridFeed.*,PV.*,.*Consumption.*&lt;br /&gt;
attr Dum.Energy alias Energiebilanz&lt;br /&gt;
attr Dum.Energy comment TotalConsumption,AutarkyQuoteDay,SelfConsumptionQuoteDay,AutarkyQuoteMonth,SelfConsumptionQuoteMonth&lt;br /&gt;
attr Dum.Energy event-on-change-reading PV,GridConsumption,GridFeedIn,SelfConsumptionQuote,Autarky.*,GridFeed.*,PV.*,.*Consumption.*&lt;br /&gt;
attr Dum.Energy event-on-update-reading TotalConsumption,AutarkyQuoteDay,SelfConsumptionQuoteDay,AutarkyQuoteMonth,SelfConsumptionQuoteMonth&lt;br /&gt;
attr Dum.Energy group Energiebilanz&lt;br /&gt;
attr Dum.Energy icon measure_power_meter&lt;br /&gt;
attr Dum.Energy room Strom-&amp;gt;Energie&lt;br /&gt;
attr Dum.Energy stateFormat {\&lt;br /&gt;
 my $pvt   = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVTotal&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $pvtd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVTotalDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $pvtm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVTotalMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $pvty  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVTotalYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $pv  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PV&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $pvd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $pvm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $pvy  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;PVYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
\&lt;br /&gt;
 my $gfi  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridFeedIn&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $gfid = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridFeedInDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $gfim = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridFeedInMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $gfiy = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridFeedInYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $eb   = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridConsumption&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $ebd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridConsumptionDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $ebm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridConsumptionMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $eby  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;GridConsumptionYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $et   = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;TotalConsumption&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; W&amp;quot;;;\&lt;br /&gt;
 my $etd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;TotalConsumptionDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $etm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;TotalConsumptionMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $ety  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;TotalConsumptionYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; kWh&amp;quot;;;\&lt;br /&gt;
 my $aq   = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;AutarkyQuote&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $aqd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;AutarkyQuoteDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $aqm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;AutarkyQuoteMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $aqy  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;AutarkyQuoteYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $sq   = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SelfConsumptionQuote&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $sqd  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SelfConsumptionQuoteDay&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $sqm  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SelfConsumptionQuoteMonth&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $sqy  = ReadingsVal(&amp;quot;$name&amp;quot;,&amp;quot;SelfConsumptionQuoteYear&amp;quot;, &amp;quot;&amp;quot;).&amp;quot; %&amp;quot;;;\&lt;br /&gt;
 my $md   = ReadingsTimestamp(&amp;quot;$name&amp;quot;, &amp;quot;AutarkyQuote&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
 my $cd   = ReadingsTimestamp(&amp;quot;PV_Anlage_1&amp;quot;, &amp;quot;Statistic_Autarky_Day&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
 my $cm   = ReadingsTimestamp(&amp;quot;PV_Anlage_1&amp;quot;, &amp;quot;Statistic_Autarky_Month&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
 my $cy   = ReadingsTimestamp(&amp;quot;PV_Anlage_1&amp;quot;, &amp;quot;Statistic_Autarky_Year&amp;quot;, &amp;quot;&amp;quot;);;\&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;table border=2 bordercolor=&#039;darkgreen&#039; cellspacing=0&amp;gt;\&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt; &amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;aktueller Wert&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;Heute&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;dieser Monat&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;font-weight:bold&#039;&amp;gt;dieses Jahr&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;PV-Erzeugung-Total&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvt.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvtd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvtm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvty.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;PV-Einspeisung&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$gfi.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$gfid.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$gfim.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$gfiy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Netz-Bezug&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$eb.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$ebd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$ebm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$eby.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;PV-Bezug&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pv.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$pvy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Energieverbrauch&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$et.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$etd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$etm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$ety.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Autarkiequote&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$aq.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$aqd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$aqm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$aqy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Eigenverbrauchsquote&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$sq.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$sqd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$sqm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$sqy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;tr&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px;;text-align:left;;font-weight:bold&#039;&amp;gt;Berechnung am&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$md.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$cd.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$cm.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;td style=&#039;padding-right:5px;;padding-left:5px&#039;&amp;gt;&amp;quot;.$cy.&amp;quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\&lt;br /&gt;
 &amp;lt;/table&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;\&lt;br /&gt;
}&lt;br /&gt;
attr Dum.Energy userReadings PVTotal {round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_AC_active_power&amp;quot;,&amp;quot;&amp;quot;),0)},\&lt;br /&gt;
PVTotalDay {round( ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;, &amp;quot;&amp;quot;)/1000 ,2)},\&lt;br /&gt;
PVTotalMonth {round( ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;, &amp;quot;&amp;quot;)/1000 ,2)},\&lt;br /&gt;
PVTotalYear {round( ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;, &amp;quot;&amp;quot;)/1000 ,2)},\&lt;br /&gt;
\&lt;br /&gt;
PV {round( ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_battery&amp;quot;, &amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_PV&amp;quot;, &amp;quot;&amp;quot;) ,0)},\&lt;br /&gt;
PVDay {round( (ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;, &amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;, &amp;quot;&amp;quot;))/1000 ,2)},\&lt;br /&gt;
PVMonth {round( (ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;, &amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;, &amp;quot;&amp;quot;))/1000 ,2)},\&lt;br /&gt;
PVYear {round( (ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;, &amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;, &amp;quot;&amp;quot;))/1000 ,2)},\&lt;br /&gt;
\&lt;br /&gt;
GridFeedIn { ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0)&amp;lt;=0 ? abs(round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0),0)) : 0  },\&lt;br /&gt;
GridFeedInDay {round((ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_Yield_Day&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;, &amp;quot;&amp;quot;))/1000,2)},\&lt;br /&gt;
GridFeedInMonth {round((ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_Yield_Month&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;, &amp;quot;&amp;quot;))/1000,2)},\&lt;br /&gt;
GridFeedInYear {round((ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_Yield_Year&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;, &amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;, &amp;quot;&amp;quot;))/1000,2)},\&lt;br /&gt;
\&lt;br /&gt;
GridConsumption { ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0)&amp;gt;=0 ? round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_active_power_(powermeter)&amp;quot;,0),0) : 0  },\&lt;br /&gt;
GridConsumptionDay {round(abs(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Day&amp;quot;,&amp;quot;&amp;quot;))/1000 ,2)},\&lt;br /&gt;
GridConsumptionMonth {round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Month&amp;quot;,&amp;quot;&amp;quot;)/1000 ,2)},\&lt;br /&gt;
GridConsumptionYear {round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Year&amp;quot;,&amp;quot;&amp;quot;)/1000 ,2)},\&lt;br /&gt;
\&lt;br /&gt;
TotalConsumption {round((ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_PV&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_battery&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_grid&amp;quot;,&amp;quot;&amp;quot;)),0)},\&lt;br /&gt;
\&lt;br /&gt;
TotalConsumptionDay {round( (ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Day&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Day&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Day&amp;quot;,&amp;quot;&amp;quot;) )/1000 ,2)},\&lt;br /&gt;
TotalConsumptionMonth {round( (ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Month&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Month&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Month&amp;quot;,&amp;quot;&amp;quot;) )/1000 ,2)},\&lt;br /&gt;
TotalConsumptionYear {round( (ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomePv_Year&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomeBat_Year&amp;quot;,&amp;quot;&amp;quot;)+ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_EnergyHomeGrid_Year&amp;quot;,&amp;quot;&amp;quot;) )/1000,2)},\&lt;br /&gt;
\&lt;br /&gt;
AutarkyQuote {my $valA = ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;, &amp;quot;Total_AC_active_power&amp;quot;,&amp;quot;&amp;quot;)-ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;, &amp;quot;Home_own_consumption_from_grid&amp;quot;,&amp;quot;&amp;quot;);; my $calcVal = ($valA &amp;gt; 0)?round($valA /($valA + ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;, &amp;quot;Home_own_consumption_from_grid&amp;quot;,&amp;quot;&amp;quot;))*100 ,0) : 0 ;; ($calcVal &amp;gt; 100)?100:$calcVal },\&lt;br /&gt;
AutarkyQuoteDay {round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_Autarky_Day&amp;quot;, &amp;quot;&amp;quot;),0)},\&lt;br /&gt;
AutarkyQuoteMonth {round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_Autarky_Month&amp;quot;, &amp;quot;&amp;quot;),0)},\&lt;br /&gt;
AutarkyQuoteYear {round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_Autarky_Year&amp;quot;, &amp;quot;&amp;quot;),0)},\&lt;br /&gt;
\&lt;br /&gt;
SelfConsumptionQuote {my $valS = ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Total_AC_active_power&amp;quot;, 0) ;; my $calcVal = ($valS &amp;gt; 0)?round((ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_PV&amp;quot;, &amp;quot;0&amp;quot;) + ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Home_own_consumption_from_battery&amp;quot;,&amp;quot;0&amp;quot;)) / $valS * 100 ,0) : 0 ;; ($calcVal &amp;gt; 100)?100:$calcVal},\&lt;br /&gt;
SelfConsumptionQuoteDay {round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_OwnConsumptionRate_Day&amp;quot;, &amp;quot;&amp;quot;),0)},\&lt;br /&gt;
SelfConsumptionQuoteMonth {round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_OwnConsumptionRate_Month&amp;quot;, &amp;quot;&amp;quot;),0)},\&lt;br /&gt;
SelfConsumptionQuoteYear {round(ReadingsVal(&amp;quot;PV_Anlage_1&amp;quot;,&amp;quot;Statistic_OwnConsumptionRate_Year&amp;quot;, &amp;quot;&amp;quot;),0)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Erstellen von zusätzlichen Werten in der Datenbank ===&lt;br /&gt;
Hier werden Werte konsolidiert, weil z.B. der Wert PV_total_Month stetig steigt. Am Ende des Monats sind die gesamten Zwischenwerte ohne Aussagekraft.&lt;br /&gt;
&lt;br /&gt;
==== RAW Definition LogDBRep_PV_total_diff_Week ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_total_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week device Dum.Energy&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week reading PVTotalMonth&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_PV_total_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition LogDBRep_PV_total_max_Month ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_total_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_total_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_total_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_PV_total_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_total_max_Month device Dum.Energy&lt;br /&gt;
attr LogDBRep_PV_total_max_Month reading PVTotalMonth&lt;br /&gt;
attr LogDBRep_PV_total_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_PV_total_max_Month timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_PV_total_max_Month timestamp_end previous_day_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition LogDBRep_PV_used_diff_Week ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_used_diff_Week DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week aggregation week&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week device Dum.Energy&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week reading PVMonth&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_PV_used_diff_Week timestamp_end previous_week_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition LogDBRep_PV_used_max_Month ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LogDBRep_PV_used_max_Month DbRep LogDB&lt;br /&gt;
attr LogDBRep_PV_used_max_Month DbLogExclude .*&lt;br /&gt;
attr LogDBRep_PV_used_max_Month aggregation month&lt;br /&gt;
attr LogDBRep_PV_used_max_Month allowDeletion 0&lt;br /&gt;
attr LogDBRep_PV_used_max_Month device Dum.Energy&lt;br /&gt;
attr LogDBRep_PV_used_max_Month reading PVMonth&lt;br /&gt;
attr LogDBRep_PV_used_max_Month room Strom-&amp;gt;Energie,System&lt;br /&gt;
attr LogDBRep_PV_used_max_Month timestamp_begin previous_month_begin&lt;br /&gt;
attr LogDBRep_PV_used_max_Month timestamp_end previous_month_end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Timing für die Datenbank Einträge ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DF_DB_Service DOIF ## Monatlich Einträge\&lt;br /&gt;
([01:13] and ($mday==1))(\&lt;br /&gt;
  set LogDBRep_PV_used_max_Month maxValue writeToDB;;\&lt;br /&gt;
  set LogDBRep_PV_total_max_Month maxValue writeToDB\&lt;br /&gt;
  )\&lt;br /&gt;
## Wöchentliche Einträge\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
([01:17] and ($wday==1))(\&lt;br /&gt;
  set LogDBRep_PV_used_diff_Week diffValue writeToDB;;\&lt;br /&gt;
  set LogDBRep_PV_total_diff_Week diffValue writeToDB\&lt;br /&gt;
  )\&lt;br /&gt;
&lt;br /&gt;
attr DF_DB_Service DbLogExclude .*&lt;br /&gt;
attr DF_DB_Service do always&lt;br /&gt;
attr DF_DB_Service room System&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Löschen von nicht mehr benötigten Werten in der Datenbank ===&lt;br /&gt;
Hier wird endgültig aufgeräumt, alte momentan Werte werden gelöscht, wenn sie nach z.B. drei Monaten keine Relevanz mehr haben. Dafür wurden im vorherigen Abschnitt zusätzliche Werte in der Datenbank erzeugt, die in Diagrammen trotzdem noch einen trend erkennen lassen.&lt;br /&gt;
Wen eine immer größer werdende Datenbank mit steigenden Antwortzeiten nicht stört, der kann das Aufräumen auch weg lassen. Bei einer späteren Migration führt dies natürlich zu höherem Aufwand und hohen Laufzeiten.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wetter-/Leistungs-Prognose ==&lt;br /&gt;
Dies ist ein Thema, dass nicht wirklich gut zu fassen ist und ist eher etwas für Enthusiasten :-), wer schon mal mit Sonne, Wolken und Regen gerechnet hat versteht was ich meine. Dieser Ansatz ist nicht wissenschaftlicher Art und hat auch keinen Anspruch mathematischer Perfektion. Nach reinem Gefühl und mit aus dem Fenster schauen kommt jedoch ein respektables Ergebnis dabei heraus. Viel Vergnügen und Spaß beim mitbasteln ;-)&lt;br /&gt;
[[Bild:Plenticore_Forecast_Tagesanfang.png|mini|900px|rechts|Wenn der Tag begonnen hat ist die Prognose vom Vortag bereits im Diagramm. Der Wert Calculation in schwarz ist die aktuelle Korrektur.]]&lt;br /&gt;
=== Deutscher Wetter Dienst (DWD) ===&lt;br /&gt;
Der DWD liefert über Mosmix kostenlos, stunden aktuelle Prognosedaten. Über einen Link am Ende dieser Seite kommt man zum &amp;quot;Photovoltaikforum&amp;quot;, wo dieses Thema erarbeitet wurde, weshalb ich es hier nicht wiederholen möchte.&lt;br /&gt;
Über Mosmix werden für diese Anwendung die Werte Rad1h und TTT bezogen, was der globalen Sonneneinstrahlung und der Temperatur entspricht.&lt;br /&gt;
Die Daten werden ins Gerät &amp;quot;DWD_Prognose&amp;quot; in das reading &amp;quot;output&amp;quot; als JSON String geschrieben und dort in readings ausgepackt.&lt;br /&gt;
Der Trigger erfolgt über das DOIF PV_Schedule , die Abholzeiten muss man noch auf die eigenen Belange anpassen, damit man nicht abholt bevor die Daten vom DWD bereit stehen. Hier gibt es oftmals Verzögerungen von über einer Stunde, was man auf dem FTP Server am Zeitstempel sehen kann. Auch hier bitte nicht zu oft abholen, damit die Server nicht überlastet werden.&lt;br /&gt;
==== Daten abholen und auspacken ====&lt;br /&gt;
fhem@raspberrypi:~/python/bin$ cat dwd_get_forecast.py &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
#  Copyright (C) 2020  Kilian Knoll kilian.knoll@gmx.de&lt;br /&gt;
#  &lt;br /&gt;
#  This program is free software: you can redistribute it and/or modify&lt;br /&gt;
#  it under the terms of the GNU General Public License as published by&lt;br /&gt;
#  the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
#  (at your option) any later version.&lt;br /&gt;
#&lt;br /&gt;
#  This program is distributed in the hope that it will be useful,&lt;br /&gt;
#  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
#  GNU General Public License for more details.&lt;br /&gt;
#&lt;br /&gt;
#  You should have received a copy of the GNU General Public License&lt;br /&gt;
#  along with this program.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
#&lt;br /&gt;
# Purpose &lt;br /&gt;
#Extract weather forecast data from DWD Mosmix for a given Station ID&lt;br /&gt;
#&lt;br /&gt;
# Background information:&lt;br /&gt;
# DWD provides 10 day forecast weather - and radiation data at an hourly resolution for over 5000 Stations worldwide (focus is on Germany/Europe though...)&lt;br /&gt;
# Description of kml file:&lt;br /&gt;
#https://www.dwd.de/DE/leistungen/opendata/help/schluessel_datenformate/kml/mosmix_elemente_pdf.pdf?__blob=publicationFile&amp;amp;v=3&lt;br /&gt;
#&lt;br /&gt;
#List of available stations:&lt;br /&gt;
#https://www.dwd.de/DE/leistungen/met_verfahren_mosmix/mosmix_stationskatalog.cfg?view=nasPublication&amp;amp;nn=495490&lt;br /&gt;
#&lt;br /&gt;
# How to use this ?&lt;br /&gt;
# 1) Find the station close by your geographic location:&lt;br /&gt;
#   Go to the website below, zoom to your location - and click on &amp;quot;Mosmix Stationen anzeigen&amp;quot; &lt;br /&gt;
#   Once you found the closest station, please change the station number to  the station number &lt;br /&gt;
#   https://wettwarn.de/mosmix/mosmix.html&lt;br /&gt;
#   In my case, I picked Station P755 (which is close to Munich)&lt;br /&gt;
# 2) Make changes in code below to reflect your station number - and the corresponding URL&lt;br /&gt;
#   change&lt;br /&gt;
#       self.mystation = P755&lt;br /&gt;
#   below to the one you identified during step 1&lt;br /&gt;
#   change the URL further down below to reflect the station:&lt;br /&gt;
# self.urlpath = &#039;https://opendata.dwd.de/weather/local_forecasts/mos/MOSMIX_L/single_stations/P755/kml&#039; &lt;br /&gt;
# Your one time setup is done...&lt;br /&gt;
# &lt;br /&gt;
# Implementation&lt;br /&gt;
# DWD provides two types of kml files&lt;br /&gt;
# single station kml files. These get updated approx every 6 hours&lt;br /&gt;
# all stations. These get updated hourly. However the file is pretty large. On embedded systems such as raspberry pi, I ran out of memory trying to parse XML files that size (exceeded 1GB of memory). Hence the decision to use the single station files&lt;br /&gt;
# we are only looking for a couple of key parameters that are relevant &lt;br /&gt;
#Currently the following Parameters get extracted from the kml file and put into a twodimensional array:&lt;br /&gt;
#mytimestamp : Timestamp of the forecast  data&lt;br /&gt;
#Rad1h       : Radiation Energy [kj/m²]&lt;br /&gt;
#TTT         : Temperature 2 m above surface [°C]&lt;br /&gt;
#PPPP        : Presssure Values (Surface Pressure reduced)&lt;br /&gt;
#FF          : Wind speed [m/s]&lt;br /&gt;
# &lt;br /&gt;
# &lt;br /&gt;
# Update August 05 2020&lt;br /&gt;
# Kilian did a lot of perfect prework, but I did some cleanup on this code. Originally it was written for a different environment.&lt;br /&gt;
# The changes are related to the communication with FHEM and the code is triggered also by FHEM for a one time run each call.&lt;br /&gt;
# Unnessesary data is dropped, to reduce the amount of data transfered to FHEM&lt;br /&gt;
&lt;br /&gt;
import urllib.request&lt;br /&gt;
import shutil&lt;br /&gt;
import zipfile&lt;br /&gt;
from bs4 import BeautifulSoup&lt;br /&gt;
import requests&lt;br /&gt;
import xml.etree.ElementTree as ET&lt;br /&gt;
import time&lt;br /&gt;
import datetime&lt;br /&gt;
import queue&lt;br /&gt;
import threading&lt;br /&gt;
import logging&lt;br /&gt;
import pprint&lt;br /&gt;
&lt;br /&gt;
import fhem&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
web     = sys.argv[1]&lt;br /&gt;
station = sys.argv[2]&lt;br /&gt;
&lt;br /&gt;
pp = pprint.PrettyPrinter(indent=4)&lt;br /&gt;
&lt;br /&gt;
def connvertINTtimestamptoDWD(inputstring):&lt;br /&gt;
    # Purpose: Convert a timestamp as presented by the UTC: 1545030000.0&lt;br /&gt;
    # and return it to a UTC representation: 2018-12-17T08:00:00.000000Z&lt;br /&gt;
    #mynewtime =time.mktime(datetime.datetime.strptime(inputstring, &amp;quot;%Y-%m-%dT%H:%M:%S.%fZ&amp;quot;).timetuple())&lt;br /&gt;
    #print (&amp;quot;neue Zeit &amp;quot;, mynewtime)&lt;br /&gt;
    mysecondtime = (datetime.datetime.fromtimestamp(inputstring).strftime(&#039;%Y-%m-%dT%H:%M:%S.%f&#039;)[:-3]) + &amp;quot;Z&amp;quot;     &lt;br /&gt;
    return (mysecondtime)  &lt;br /&gt;
&lt;br /&gt;
# Main class that holds the required information &lt;br /&gt;
class dwdforecast(threading.Thread):&lt;br /&gt;
    def __init__ (self, myqueue):&lt;br /&gt;
        print (&amp;quot;Starting dwdforecast init ...&amp;quot;)&lt;br /&gt;
        self.myqueue = myqueue&lt;br /&gt;
        self.event = threading.Event()&lt;br /&gt;
        self.ext = &#039;kmz&#039;&lt;br /&gt;
        self.mystation = station                            # This should be your closes station&lt;br /&gt;
        # Only use the &amp;quot;all_stations&amp;quot; if you got decent hardware&lt;br /&gt;
        #self.urlpath = &#039;http://opendata.dwd.de/weather/local_forecasts/mos/MOSMIX_S/all_stations/kml&#039;&lt;br /&gt;
        #On Raspberries &amp;amp; alikes, use the one for your specific station: &lt;br /&gt;
        self.urlpath = &#039;https://opendata.dwd.de/weather/local_forecasts/mos/MOSMIX_L/single_stations/&#039; + self.mystation +&#039;/kml&#039;&lt;br /&gt;
        self.lasttimecheck = 1534800680.0                   # Dec 14th 2018 (pure initialization)&lt;br /&gt;
        self.sleeptime = 15                                 #Time interval we poll the server [seconds]- please increase time since updates from DWD are hourly at best&lt;br /&gt;
        self.myinit = 0                                                                                     #So we can populate the queue initially / subsequently&lt;br /&gt;
        threading.Thread.__init__ (self)&lt;br /&gt;
        print (&amp;quot;I am looking for data from DWD for the following station: &amp;quot;, self.mystation)&lt;br /&gt;
        print (&amp;quot;I will be polling the following URL for the latest updates &amp;quot;, self.urlpath)&lt;br /&gt;
&lt;br /&gt;
    # Based on the user specified URL, find the latest file file with it´s timestamp &lt;br /&gt;
    def GetURLForLatest(self,urlpath, ext=&#039;&#039;):&lt;br /&gt;
        try:&lt;br /&gt;
            page = requests.get(urlpath).text&lt;br /&gt;
        except Exception as ErrorGetWebdata:&lt;br /&gt;
            logging.error(&amp;quot;%s %s&amp;quot;,&amp;quot;,GetURLForLatest Error getting data from the internet:&amp;quot;, ErrorGetWebdata)&lt;br /&gt;
        soup = BeautifulSoup(page, &#039;html.parser&#039;)&lt;br /&gt;
        soup_reduced= soup.find_all(&#039;pre&#039;)&lt;br /&gt;
        soup_reduced = soup_reduced[0]&lt;br /&gt;
        counter = 0&lt;br /&gt;
        for elements in soup_reduced:&lt;br /&gt;
            elements = str(elements)&lt;br /&gt;
            if (counter &amp;gt;0):&lt;br /&gt;
                words =elements.split()&lt;br /&gt;
                mytime = words[0] +&amp;quot;-&amp;quot; + words[1]&lt;br /&gt;
                logging.debug(&amp;quot;%s %s&amp;quot; ,&amp;quot;,GetURLForLatest :DWD Filetimestamp found :&amp;quot;, mytime)&lt;br /&gt;
                mynewtime =time.mktime(datetime.datetime.strptime(mytime, &amp;quot;%d-%b-%Y-%H:%M&amp;quot;).timetuple())&lt;br /&gt;
                logging.debug(&amp;quot;%s %s&amp;quot; ,&amp;quot;,GetURLForLatest :DWD Filetimestamp found :&amp;quot;, mynewtime)&lt;br /&gt;
                #print (&amp;quot;From function GetURLForLatest -mynewtime&amp;quot;, 2*mynewtime)&lt;br /&gt;
            &lt;br /&gt;
            if (elements.find(&amp;quot;LATEST&amp;quot;) &amp;gt;0):&lt;br /&gt;
                #print (&amp;quot;My element&amp;quot;, elements)&lt;br /&gt;
                counter = 1&lt;br /&gt;
        myurl = [urlpath + &#039;/&#039; + node.get(&#039;href&#039;) for node in soup.find_all(&#039;a&#039;) if node.get(&#039;href&#039;).endswith(ext)]&lt;br /&gt;
        return (myurl, mynewtime)&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
    def connvertDWDtimestamptoINT(self,inputstring):&lt;br /&gt;
        # Purpose: Convert a timestamp as presented by the DWD: 2018-12-25T07:00:00.000Z&lt;br /&gt;
        # and return it to a UTC representation&lt;br /&gt;
        mynewtime =time.mktime(datetime.datetime.strptime(inputstring, &amp;quot;%Y-%m-%dT%H:%M:%S.%fZ&amp;quot;).timetuple())&lt;br /&gt;
        #print (&amp;quot;neue Zeit &amp;quot;, mynewtime)&lt;br /&gt;
        #mysecondtime = datetime.datetime.fromtimestamp(mynewtime).strftime(&#039;%Y-%m-%dT%H:%M:%S.%fZ&#039;)     &lt;br /&gt;
        #print (&amp;quot;Einmal retour&amp;quot;, mysecondtime)&lt;br /&gt;
        mycurrentINTtimestamp =int(mynewtime)&lt;br /&gt;
        return (mycurrentINTtimestamp)&lt;br /&gt;
   &lt;br /&gt;
    &lt;br /&gt;
    def connvertDWDtimestamptoINT(self,inputstring):&lt;br /&gt;
        # Purpose: Convert a timestamp as presented by the DWD: 2018-12-25T07:00:00.000Z&lt;br /&gt;
        # and return it to a UTC representation&lt;br /&gt;
        mynewtime =time.mktime(datetime.datetime.strptime(inputstring, &amp;quot;%Y-%m-%dT%H:%M:%S.%fZ&amp;quot;).timetuple())&lt;br /&gt;
        mycurrentINTtimestamp =int(mynewtime)&lt;br /&gt;
        return (mycurrentINTtimestamp)&lt;br /&gt;
 &lt;br /&gt;
    try:&lt;br /&gt;
        def run(self):&lt;br /&gt;
            if (self.myinit== 0):                 #We populate the first timestamp to signal to main that we are up &amp;amp; running&lt;br /&gt;
                temptimestamp = time.time()&lt;br /&gt;
                print (&amp;quot;From dwdforecast - initial queue population&amp;quot;, temptimestamp)&lt;br /&gt;
                self.myqueue.put(temptimestamp)&lt;br /&gt;
                self.myinit = 1&lt;br /&gt;
            time.sleep(1)&lt;br /&gt;
            try:&lt;br /&gt;
                self.mydownloadfiles, self.mynewtime = self.GetURLForLatest(self.urlpath, self.ext)&lt;br /&gt;
                #print (&amp;quot;Downloadfiles = &amp;quot;, self.mydownloadfiles)&lt;br /&gt;
                #print (&amp;quot;Timestamp    = &amp;quot;, self.mynewtime)&lt;br /&gt;
            except Exception as ErrorReadFromDWD:&lt;br /&gt;
                logging.error(&amp;quot;%s %s&amp;quot; ,&amp;quot;,dwdforecast  :&amp;quot;, ErrorReadFromDWD)&lt;br /&gt;
            &lt;br /&gt;
            self.myarray =[]&lt;br /&gt;
            for self.file in self.mydownloadfiles:&lt;br /&gt;
                self.myarray.append(self.file)&lt;br /&gt;
            self.temp_length = len(self.myarray)&lt;br /&gt;
            self.url = self.myarray[self.temp_length-1]&lt;br /&gt;
&lt;br /&gt;
            logging.debug(&amp;quot;%s %s %s&amp;quot;,&amp;quot;,dwdforecast : -BEFORE  if- time comparison :&amp;quot;, self.mynewtime, self.lasttimecheck)                &lt;br /&gt;
#              if (self.mynewtime &amp;gt; self.lasttimecheck):&lt;br /&gt;
            logging.debug(&amp;quot;%s %s %s&amp;quot; ,&amp;quot;,dwdforecast : -in if- time comparison :&amp;quot;, self.mynewtime, self.lasttimecheck)&lt;br /&gt;
            #print (&amp;quot;DWD Weather - we have found a new kml file that we will download - timestamp was :&amp;quot;, self.mynewtime)&lt;br /&gt;
            #print (&amp;quot;DWD Weather -  self.lasttimecheck was &amp;quot;, self.lasttimecheck)&lt;br /&gt;
            self.lasttimecheck = self.mynewtime&lt;br /&gt;
            self.file_name = &amp;quot;dwd_temp1.gz&amp;quot;&lt;br /&gt;
            self.out_file = &amp;quot;dwd_temp2.gz&amp;quot;&lt;br /&gt;
            self.targetdir =&amp;quot;./&amp;quot;&lt;br /&gt;
            try:&lt;br /&gt;
                    time.sleep(10)                                          #Assumption is - we see the file on the DWD server - but it has not yet been copied over&lt;br /&gt;
                    # Download the file from `url` and save it locally under `self.file_name`:&lt;br /&gt;
                    with urllib.request.urlopen(self.url) as self.response, open(self.file_name, &#039;wb&#039;) as self.out_file:&lt;br /&gt;
                        shutil.copyfileobj(self.response, self.out_file)&lt;br /&gt;
                    time.sleep(5)                                           #not sure if this gets rid of the access problems                  &lt;br /&gt;
                    with zipfile.ZipFile(self.file_name,&amp;quot;r&amp;quot;) as zip_ref:&lt;br /&gt;
                        Myzipfilename = (zip_ref.namelist())&lt;br /&gt;
                        Myzipfilename = str(Myzipfilename[0])&lt;br /&gt;
                        zip_ref.extractall(self.targetdir)    &lt;br /&gt;
                    logging.debug(&amp;quot;%s %s&amp;quot; ,&amp;quot;,dwdforecast : -File that I extract is zipfile :&amp;quot;, Myzipfilename)&lt;br /&gt;
                    time.sleep(5)                                           #not sure if this gets rid of the access problems&lt;br /&gt;
            except Exception as MyException:&lt;br /&gt;
                    logging.error(&amp;quot;%s %s&amp;quot;, &amp;quot;,subroutine dwdforecast exception getting the data from server : &amp;quot;, MyException)    &lt;br /&gt;
                        &lt;br /&gt;
            self.tree = ET.parse(Myzipfilename) &lt;br /&gt;
            self.root = self.tree.getroot()&lt;br /&gt;
            self.root.tag     &lt;br /&gt;
            &amp;quot;&amp;quot;&amp;quot;      &lt;br /&gt;
            &amp;lt;kml:kml xmlns:dwd=&amp;quot;https://opendata.dwd.de/weather/lib/pointforecast_dwd_extension_V1_0.xsd&amp;quot; xmlns:gx=&amp;quot;http://www.google.com/kml/ext/2.2&amp;quot; xmlns:xal=&amp;quot;urn:oasis:names:tc:ciq:xsdschema:xAL:2.0&amp;quot; xmlns:kml=&amp;quot;http://www.opengis.net/kml/2.2&amp;quot; xmlns:atom=&amp;quot;http://www.w3.org/2005/Atom&amp;quot;&amp;gt;&lt;br /&gt;
                        &lt;br /&gt;
            &amp;lt;kml:kml xmlns:dwd=&amp;quot;https://opendata.dwd.de/weather/lib/pointforecast_dwd_extension_V1_0.xsd&amp;quot; xmlns:gx=&amp;quot;http://www.google.com/kml/ext/2.2&amp;quot; xmlns:xal=&amp;quot;urn:oasis:names:tc:ciq:xsdschema:xAL:2.0&amp;quot; xmlns:kml=&amp;quot;http://www.opengis.net/kml/2.2&amp;quot; xmlns:atom=&amp;quot;http://www.w3.org/2005/Atom&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
            #--------------------------------------------------&lt;br /&gt;
            #Namespace definition for kml file:&lt;br /&gt;
            #&lt;br /&gt;
            self.ns = {&#039;dwd&#039;: &#039;https://opendata.dwd.de/weather/lib/pointforecast_dwd_extension_V1_0.xsd&#039;, &#039;gx&#039;: &#039;http://www.google.com/kml/ext/2.2&#039;,&lt;br /&gt;
            &#039;kml&#039;: &#039;http://www.opengis.net/kml/2.2&#039;, &#039;atom&#039;: &#039;http://www.w3.org/2005/Atom&#039;, &#039;xal&#039;:&#039;urn:oasis:names:tc:ciq:xsdschema:xAL:2.0&#039;}&lt;br /&gt;
                #--------------------------------------------------&lt;br /&gt;
                # We get the timestamps&lt;br /&gt;
                #&lt;br /&gt;
            self.timestamps = self.root.findall(&#039;kml:Document/kml:ExtendedData/dwd:ProductDefinition/dwd:ForecastTimeSteps/dwd:TimeStep&#039;,self.ns)&lt;br /&gt;
            self.i = 0&lt;br /&gt;
            self.timevalue=[]&lt;br /&gt;
            for self.child in self.timestamps:&lt;br /&gt;
                #print (&amp;quot;TIMESTAMPS&amp;quot;,  child.text)&lt;br /&gt;
                self.timevalue.append(self.child.text)&lt;br /&gt;
            &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
            for j in timevalue:&lt;br /&gt;
                print (&amp;quot;Zeit&amp;quot;,i, &amp;quot; &amp;quot;, timevalue[i])&lt;br /&gt;
                i = i+1&lt;br /&gt;
            &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
                        &lt;br /&gt;
            for self.elem in self.tree.findall(&#039;./kml:Document/kml:Placemark&#039;,self.ns):                    #Position us at the Placemark&lt;br /&gt;
                #print (&amp;quot;SUCERJH &amp;quot;, sucher)&lt;br /&gt;
                #print (&amp;quot;Elemente &amp;quot;, elem.tag, elem.attrib, elem.text)&lt;br /&gt;
                self.mylocation = self.elem.find(&#039;kml:name&#039;,self.ns).text                                  #Look for the station Number&lt;br /&gt;
                        &lt;br /&gt;
                # Hier IF Frage einbauen&lt;br /&gt;
                if (self.mylocation == self.mystation):   &lt;br /&gt;
                    #print (&amp;quot;meine location&amp;quot;, self.mylocation)&lt;br /&gt;
                    self.myforecastdata = self.elem.find(&#039;kml:ExtendedData&#039;,self.ns)&lt;br /&gt;
                    for self.elem in self.myforecastdata:                                         &lt;br /&gt;
                        #We may get the following strings and are only interested in the right hand quoted property name WPcd1:&lt;br /&gt;
                        #{&#039;{https://opendata.dwd.de/weather/lib/pointforecast_dwd_extension_V1_0.xsd}elementName&#039;: &#039;WPcd1&#039;}&lt;br /&gt;
                        self.trash = str(self.elem.attrib)&lt;br /&gt;
                        self.trash1,self.mosmix_element = self.trash.split(&amp;quot;&#039;: &#039;&amp;quot;)&lt;br /&gt;
                        self.mosmix_element, self.trash = self.mosmix_element.split(&amp;quot;&#039;}&amp;quot;)&lt;br /&gt;
                        #-------------------------------------------------------------&lt;br /&gt;
                        # Currently looking at the following key Data:&lt;br /&gt;
                        # Looking for the following mosmix_elements &lt;br /&gt;
                        #FF : Wind Speed            [m/s]&lt;br /&gt;
                        #Rad1h : Global irridance   [kJ/m²]&lt;br /&gt;
                        #TTT : Temperature 2m above ground [Kelvin]&lt;br /&gt;
                        #PPPP : Pressure reduced    [Pa]&lt;br /&gt;
                        #-------------------------------------------------------------&lt;br /&gt;
                        if (&#039;FF&#039; == self.mosmix_element):&lt;br /&gt;
                            self.FF_temp = self.elem[0].text&lt;br /&gt;
                            self.FF = list (self.FF_temp.split())&lt;br /&gt;
                        if (&#039;Rad1h&#039; == self.mosmix_element):&lt;br /&gt;
                            self.Rad1h_temp = self.elem[0].text&lt;br /&gt;
                            self.Rad1h = list (self.Rad1h_temp.split())&lt;br /&gt;
                        if (&#039;TTT&#039; == self.mosmix_element):&lt;br /&gt;
                            self.TTT_temp = self.elem[0].text&lt;br /&gt;
                            self.TTT = list(self.TTT_temp.split())&lt;br /&gt;
                            counter = 0 &lt;br /&gt;
                            # We convert from Kelvin to Celcius...:&lt;br /&gt;
                            for i in self.TTT:&lt;br /&gt;
                                self.TTT[counter]=round((float(self.TTT[counter])-273.13),2)&lt;br /&gt;
                                #print (self.TTT[counter])&lt;br /&gt;
                                counter = counter +1&lt;br /&gt;
                        if (&#039;PPPP&#039; == self.mosmix_element):&lt;br /&gt;
                            self.PPPP_temp = self.elem[0].text&lt;br /&gt;
                            self.PPPP = list (self.PPPP_temp.split())&lt;br /&gt;
                    &lt;br /&gt;
                    &lt;br /&gt;
                    #------------------------------------&lt;br /&gt;
                    # Define empty array                &lt;br /&gt;
                self.mosmixdata =[]&lt;br /&gt;
                for self.j in range(6):                                      #Right now we have timevalue, mytimestamp, self.FF Rad1h TTT PPPP&lt;br /&gt;
                    self.column = []&lt;br /&gt;
                    self.counter = 0&lt;br /&gt;
                    for self.i in self.timevalue:&lt;br /&gt;
                        self.column.append(0)&lt;br /&gt;
                    self.mosmixdata.append(self.column)&lt;br /&gt;
                    #------------------------------------&lt;br /&gt;
                    #Populate values&lt;br /&gt;
                counter = 0&lt;br /&gt;
                    &lt;br /&gt;
                for self.i in self.timevalue:&lt;br /&gt;
                    self.mytimestamp = self.connvertDWDtimestamptoINT(self.timevalue[counter])&lt;br /&gt;
                    self.mosmixdata[0][counter]=self.timevalue[counter]&lt;br /&gt;
                    self.mosmixdata[1][counter]=self.mytimestamp&lt;br /&gt;
                    self.mosmixdata[2][counter]=self.Rad1h[counter]&lt;br /&gt;
                    self.mosmixdata[3][counter]=self.TTT[counter]&lt;br /&gt;
                    self.mosmixdata[4][counter]=self.PPPP[counter]&lt;br /&gt;
                    self.mosmixdata[5][counter]=self.FF[counter]&lt;br /&gt;
                    counter = counter + 1&lt;br /&gt;
                    #------------------------------------------&lt;br /&gt;
&lt;br /&gt;
            self.cols = len(self.mosmixdata)&lt;br /&gt;
            rows = 0&lt;br /&gt;
            if self.cols:&lt;br /&gt;
                self.rows = len(self.mosmixdata[0])&lt;br /&gt;
            self.MosmixFileFirsttimestamp = self.mosmixdata[1][0]&lt;br /&gt;
                #print (&amp;quot;My first stamp from the file is:&amp;quot;,self.mosmixdata[0][0],&amp;quot;Endstring&amp;quot;,self.mosmixdata[1][0] )       &lt;br /&gt;
                #print (&amp;quot;-------------------------------------------------&amp;quot;)&lt;br /&gt;
                #print (self.mosmixdata)&lt;br /&gt;
            self.indexcounter_addrows=1&lt;br /&gt;
            self.MyWeathervalues = {}&lt;br /&gt;
            try:&lt;br /&gt;
                print (&amp;quot;Here is what we got from DWD :&amp;quot;)&lt;br /&gt;
                for j in range(self.rows):&lt;br /&gt;
                    if (self.indexcounter_addrows &amp;gt;0):                                       #We are adding from the point onward - see self.indexcounter_addrows if check below&lt;br /&gt;
                        #print (&amp;quot;counting indices&amp;quot;, self.indexcounter_addrows)&lt;br /&gt;
                        #self.MyWeathervalues.update({&#039;mydatetime&#039;:self.mosmixdata[0][j]})&lt;br /&gt;
                        #self.MyWeathervalues.update({&#039;mytimestamp&#039;:self.mosmixdata[1][j]})&lt;br /&gt;
                        if (self.mosmixdata[2][j] &amp;gt; &#039;0.00&#039;):                                 #Reduce unneccessary data&lt;br /&gt;
                            self.time = time.strftime(&amp;quot;%Y-%m-%d_%H:%M&amp;quot;, time.localtime(self.mosmixdata[1][j]))&lt;br /&gt;
                            self.MyWeathervalues.update({self.time + &#039;_Rad1wh&#039;:int(round(float(self.mosmixdata[2][j]) * 0.277778 , 0))})&lt;br /&gt;
                            self.MyWeathervalues.update({self.time + &#039;_TTT&#039;:self.mosmixdata[3][j]})&lt;br /&gt;
                        #self.MyWeathervalues.update({&#039;TTT&#039;:self.mosmixdata[3][j]})&lt;br /&gt;
                        #self.MyWeathervalues.update({&#039;PPPP&#039;:self.mosmixdata[4][j]})&lt;br /&gt;
                        #self.MyWeathervalues.update({&#039;FF&#039;:self.mosmixdata[5][j]})  &lt;br /&gt;
&lt;br /&gt;
                        #print (&#039;mydatetime&#039;,self.mosmixdata[0][j],&#039;mytimestamp &#039;,self.mosmixdata[1][j],&#039;Rad1h &#039;,self.mosmixdata[2][j],&#039;TTT &#039;,self.mosmixdata[3][j], &#039;PPPP&#039;,self.mosmixdata[4][j],&#039;FF&#039;,self.mosmixdata[5][j])&lt;br /&gt;
&lt;br /&gt;
                import re&lt;br /&gt;
                self.message = re.sub(&amp;quot;&#039;&amp;quot;, &amp;quot;\&amp;quot;&amp;quot;, str(self.MyWeathervalues))&lt;br /&gt;
                #print(self.MyWeathervalues)&lt;br /&gt;
                #print(self.message)&lt;br /&gt;
&lt;br /&gt;
                try:&lt;br /&gt;
                    with open(&#039;/opt/fhem/python/pwd_fhem.json&#039;, &#039;r&#039;) as f:&lt;br /&gt;
                        credentials=json.load(f)&lt;br /&gt;
                except Exception as e:&lt;br /&gt;
                    print(&#039;Something went wrong: {}&#039;.format(e))&lt;br /&gt;
&lt;br /&gt;
                fh = fhem.Fhem(web, protocol=&amp;quot;http&amp;quot;, port=8083, username=credentials[&amp;quot;username&amp;quot;], password=credentials[&amp;quot;password&amp;quot;])&lt;br /&gt;
&lt;br /&gt;
                fh.send_cmd(&amp;quot;setreading DWD_Prognose output &amp;quot; + self.message)&lt;br /&gt;
&lt;br /&gt;
                        &lt;br /&gt;
                self.mytimestamp = connvertINTtimestamptoDWD(self.mynewtime)&lt;br /&gt;
                logging.debug (&amp;quot;%s %s %s %s&amp;quot;, &amp;quot;,Subroutine dwdforecast -we have used DWD file from time : &amp;quot;, self.mynewtime, &amp;quot; &amp;quot;, self.mytimestamp)&lt;br /&gt;
            except Exception as ErrorDWDArray:&lt;br /&gt;
                print (&amp;quot;Shit happened  ?&amp;quot;, ErrorDWDArray)&lt;br /&gt;
                logging.error (&amp;quot;%s %s&amp;quot;, &amp;quot;,subroutine dwdforecast final exception : &amp;quot;, ErrorDWDArray)&lt;br /&gt;
            logging.debug(&amp;quot;%s %s&amp;quot;, &amp;quot;From dwdforecast - we have found a true commit and have updated the database at the following dwd time :&amp;quot;, self.mynewtime)&lt;br /&gt;
            time.sleep(self.sleeptime)          # We are putting in a sleep &lt;br /&gt;
            self.myqueue.put(self.mynewtime)&lt;br /&gt;
&lt;br /&gt;
    except Exception as ExceptionError:&lt;br /&gt;
            print (&amp;quot;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;quot;)&lt;br /&gt;
            print (&amp;quot;XXX-Aus Subroutine dwdforecast -verrant ? &amp;quot;, ExceptionError)&lt;br /&gt;
            print (&amp;quot;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;quot;)&lt;br /&gt;
            logging.error(&amp;quot;%s %s&amp;quot;, &amp;quot;,subroutine dwdforecast final exception : &amp;quot;, ExceptionError)&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
    logging.basicConfig(filename=&amp;quot;./log/dwd_debug.txt&amp;quot;,level=logging.DEBUG)&lt;br /&gt;
    #&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Interaction can be &#039;Simple&#039; - or &#039;Complex&#039;&lt;br /&gt;
    Simple : Try to get weather data once only - then terminate&lt;br /&gt;
    Complex : Start a seperate queue that continuously polls the DWD server on the internet to get updated data &lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Interaction = &#039;Simple&#039; #Interaction can be &#039;Simple&#039; - or &#039;Complex&#039;&lt;br /&gt;
    #&lt;br /&gt;
&lt;br /&gt;
    #-----------------------------------------------------------------&lt;br /&gt;
    # START Queue (To read dwd values and populate them to database):&lt;br /&gt;
    try:&lt;br /&gt;
        myQueue1 = queue.Queue()                                               &lt;br /&gt;
        myThread1= dwdforecast(myQueue1)                          &lt;br /&gt;
        myThread1.start()                                                             &lt;br /&gt;
        while myQueue1.empty():                                                  &lt;br /&gt;
            print(&amp;quot; Waiting on DWD dwdforecastdata Queue results to tell it is started...&amp;quot;)&lt;br /&gt;
            logging.info(&amp;quot;%s &amp;quot; &amp;quot;,Main :Waiting on Queue results to be populated ...&amp;quot;)&lt;br /&gt;
            time.sleep(1)&lt;br /&gt;
        # Queue End (To read values from DWD)&lt;br /&gt;
        #_________________________________________________________________&lt;br /&gt;
        i = 0 &lt;br /&gt;
            &lt;br /&gt;
        try:&lt;br /&gt;
            while i &amp;lt;1: &lt;br /&gt;
                if not myQueue1.empty():                                      # Falls was in der Queue steht machen wir was&lt;br /&gt;
                    quelength = myQueue1.qsize()                               # Wenn da viele Werte angelaufen sind, nehmen wir jetzt einfach den Letzten&lt;br /&gt;
                    #print (&amp;quot;LAENGE der QUEUE -XXXXXXXXXXXXXXXXXXXXXXX : &amp;quot;, quelength) &lt;br /&gt;
                    logging.info(&amp;quot;%s %s &amp;quot; ,&amp;quot;,Main :Queue length is : &amp;quot;, quelength) &lt;br /&gt;
                    &lt;br /&gt;
                    for x in range (0,quelength):&lt;br /&gt;
                        LastDWDtimestamp = myQueue1.get()                     # Das ist die magische Zeile in der wir den Wert aus der Queue abholen &lt;br /&gt;
                        mylasttimestamp = connvertINTtimestamptoDWD(LastDWDtimestamp)&lt;br /&gt;
                    print (&amp;quot;From Main : DWD File access I checked /  got uploaded by DWD was at :&amp;quot;, LastDWDtimestamp,mylasttimestamp )&lt;br /&gt;
                    i = i + 1&lt;br /&gt;
&lt;br /&gt;
        except Exception as OtherExceptionError:  &lt;br /&gt;
            print (&amp;quot;hit some other error....    !&amp;quot;, OtherExceptionError)&lt;br /&gt;
            &lt;br /&gt;
                &lt;br /&gt;
    except Exception as FinalExceptionError:  &lt;br /&gt;
        print (&amp;quot;I am clueless ... Hit some other error ....    !&amp;quot;, FinalExceptionError)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition DWD_Prognose ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod DWD_Prognose expandJSON DWD_Prognose:output:.\{.*}&lt;br /&gt;
attr DWD_Prognose DbLogExclude .*&lt;br /&gt;
attr DWD_Prognose alias DWD_Prognose&lt;br /&gt;
attr DWD_Prognose comment Das Device wird über ein Python Skript im reading output befüllt.\&lt;br /&gt;
deletereading DWD_Prognose .*_Rad1wh\&lt;br /&gt;
&lt;br /&gt;
attr DWD_Prognose group PV Eigenverbrauch&lt;br /&gt;
attr DWD_Prognose icon measure_photovoltaic_inst&lt;br /&gt;
attr DWD_Prognose room Informationen-&amp;gt;Wetter,Strom-&amp;gt;Photovoltaik,Strom-&amp;gt;System&lt;br /&gt;
attr DWD_Prognose sortby 02&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== ProPlanta ===&lt;br /&gt;
Die Webseite Proplanta stellt unter anderem chOfRain*, cloud* in einer drei Stunden Prognose bereit und dies dann für mehrere Tage fc0 , fc1, ...&lt;br /&gt;
==== RAW Definition ProPlanta ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod ProPlanta PROPLANTA &amp;lt;Wohnort&amp;gt; de&lt;br /&gt;
attr ProPlanta DbLogExclude .*&lt;br /&gt;
attr ProPlanta DbLogInclude cloudBaseMax,cloudBaseMin,fc0_cloud06,fc0_cloud09,fc0_cloud12,fc0_cloud15,fc0_cloud18,fc0_rad,fc0_sun,fc0_uv,fc0_weather06,fc0_weather09,fc0_weather12,fc0_weather15,fc0_weather18,fc1_cloud06,fc1_cloud09,fc1_cloud12,fc1_cloud15,fc1_cloud18,fc1_rad,fc1_sun,fc1_uv,fc1_weather06,fc1_weather09,fc1_weather12,fc1_weather15,fc1_weather18,weather&lt;br /&gt;
attr ProPlanta INTERVAL 900&lt;br /&gt;
attr ProPlanta alias ProPlanta&lt;br /&gt;
attr ProPlanta event-on-change-reading cloudBaseMax,cloudBaseMin,fc0_cloud06,fc0_cloud09,fc0_cloud12,fc0_cloud15,fc0_cloud18,fc0_rad,fc0_sun,fc0_uv,fc0_weather06,fc0_weather09,fc0_weather12,fc0_weather15,fc0_weather18,fc1_cloud06,fc1_cloud09,fc1_cloud12,fc1_cloud15,fc1_cloud18,fc1_rad,fc1_sun,fc1_uv,fc1_weather06,fc1_weather09,fc1_weather12,fc1_weather15,fc1_weather18,weather&lt;br /&gt;
attr ProPlanta forecastDays 4&lt;br /&gt;
attr ProPlanta group ASC Environment&lt;br /&gt;
attr ProPlanta icon weather_sunrise&lt;br /&gt;
attr ProPlanta room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr ProPlanta sortby 02&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== myUtils.pm Funktionen ===&lt;br /&gt;
==== Solar_forecast ====&lt;br /&gt;
Achtung, diese Funktion ist noch nicht vollständig ausprogrammiert. Es wurden bereits Übergabeparameter integriert, um z.B. andere Wetterdienste zu berücksichtigen.&lt;br /&gt;
Um diese Funktion zu nutzen muss ein Dummy PV_Anlage_1_config vorhanden sein, in dem unter anderem die Modul und Anlagen Ausrichtung konfiguriert wird.&lt;br /&gt;
Rückfragen gerne im Forum.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
###########################################################&lt;br /&gt;
# Subroutine to calculate radiation&lt;br /&gt;
###########################################################&lt;br /&gt;
sub Solar_forecast($$$$$$$) {&lt;br /&gt;
&lt;br /&gt;
     my $logdb       = $_[0] ;&lt;br /&gt;
     my $logdbrep    = $_[1] ;        # Das wird zum Löschen in der LogDB verwendet und muss entsprechend konfiguriert sein.&lt;br /&gt;
     my $logdevice   = $_[2] ;&lt;br /&gt;
     # Hier könnte man noch andere Wetterdienste berücksichtigen bzw den Device Namen ändern&lt;br /&gt;
     my $wetter_1    = $_[4] ; if ($wetter_1 ne &amp;quot;DWD_Prognose&amp;quot;) {return(&amp;quot;$wetter_1 not supported&amp;quot;)} ;&lt;br /&gt;
     my $wetter_2    = $_[5] ; if ($wetter_2 ne &amp;quot;ProPlanta&amp;quot;   ) {return(&amp;quot;$wetter_2 not supported&amp;quot;)} ;&lt;br /&gt;
     my $fc          = $_[6] ;        # Wieviel Tage in die Zukunft soll es gehen? 0,1,2&lt;br /&gt;
     my $reading     = $_[3].$fc ;&lt;br /&gt;
&lt;br /&gt;
     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $year += 1900; $mon += 1;&lt;br /&gt;
     my ($Solar_Cloud,$Solar_Rain,$Solar_Temp,$Solar_Correction_Cloud,$Solar_Correction_Rain,$Solar_Correction_Temp,$Solar_SolarRadiation,$Solar_East,$Solar_South,$Solar_West,$logentry,$i) = 0 ;&lt;br /&gt;
     my ($Solar_1,$Solar_2,$Solar_3) = 0 ;&lt;br /&gt;
&lt;br /&gt;
     # Initialisieren des Basis TIMESTAMP für den Forecast&lt;br /&gt;
     my $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; 08:00:00&amp;quot;) ;&lt;br /&gt;
     my $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
     # Bei Forecast ab dem nächsten Tag zuerst die bisherigen Einträge für den Tag löschen&lt;br /&gt;
     if ( $fc != 0 ) {&lt;br /&gt;
        fhem &amp;quot;set &amp;quot;.$logdbrep.&amp;quot; sqlCmd DELETE FROM history WHERE DEVICE=&#039;&amp;quot;.$logdevice.&amp;quot;&#039; AND READING=&#039;&amp;quot;.$reading.&amp;quot;&#039; AND TIMESTAMP&amp;gt;=&#039;&amp;quot;.$timestamp.&amp;quot;&#039;&amp;quot;} ;&lt;br /&gt;
&lt;br /&gt;
      # Es werden Stundenwerte von 08:00 bis 19:00 Uhr berechnet&lt;br /&gt;
      for ($i = 8; $i &amp;lt;= 19; $i++) {&lt;br /&gt;
        $timestring = time_str2num($year.&amp;quot;-&amp;quot;.$mon.&amp;quot;-&amp;quot;.$mday.&amp;quot; &amp;quot;.$i.&amp;quot;:00:00&amp;quot;) ;&lt;br /&gt;
        $timestamp  = POSIX::strftime(&amp;quot;%Y-%m-%d %H:00:00&amp;quot;,localtime($timestring+$fc*24*60*60)) ;&lt;br /&gt;
&lt;br /&gt;
        # Bei ProPlanta liegen die Werte im drei Stunden Abstand vor&lt;br /&gt;
        if ( $wetter_2 eq &amp;quot;ProPlanta&amp;quot;) {&lt;br /&gt;
          if ( $i &amp;gt;=  6 and $i &amp;lt;  9 )&lt;br /&gt;
            { $Solar_Cloud = ReadingsVal($wetter_2,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_cloud09&amp;quot;   ,0) ;&lt;br /&gt;
              $Solar_Rain  = ReadingsVal($wetter_2,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_chOfRain09&amp;quot;,0) ; } ;&lt;br /&gt;
          if ( $i &amp;gt;=  9 and $i &amp;lt; 12 )&lt;br /&gt;
            { $Solar_Cloud = ReadingsVal($wetter_2,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_cloud09&amp;quot;   ,0) ;&lt;br /&gt;
              $Solar_Rain  = ReadingsVal($wetter_2,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_chOfRain09&amp;quot;,0) ; } ;&lt;br /&gt;
          if ( $i &amp;gt;= 12 and $i &amp;lt; 15 )&lt;br /&gt;
            { $Solar_Cloud = ReadingsVal($wetter_2,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_cloud12&amp;quot;   ,0) ;&lt;br /&gt;
              $Solar_Rain  = ReadingsVal($wetter_2,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_chOfRain12&amp;quot;,0) ; } ;&lt;br /&gt;
          if ( $i &amp;gt;= 15 and $i &amp;lt; 18 )&lt;br /&gt;
            { $Solar_Cloud = ReadingsVal($wetter_2,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_cloud15&amp;quot;   ,0) ;&lt;br /&gt;
              $Solar_Rain  = ReadingsVal($wetter_2,&amp;quot;fc&amp;quot;.$fc.&amp;quot;_chOfRain15&amp;quot;,0) ; } ;&lt;br /&gt;
         };&lt;br /&gt;
&lt;br /&gt;
        if ( $wetter_1 eq &amp;quot;DWD_Prognose&amp;quot;) {&lt;br /&gt;
          $Solar_Temp           = ReadingsVal($wetter_1,POSIX::strftime(&amp;quot;%Y-%m-%d_%H_00_TTT&amp;quot;,   localtime($timestring+($fc*24-1)*60*60)),0)+10;&lt;br /&gt;
          $Solar_SolarRadiation = ReadingsVal($wetter_1,POSIX::strftime(&amp;quot;%Y-%m-%d_%H_00_Rad1wh&amp;quot;,localtime($timestring+($fc*24-1)*60*60)),0) ;&lt;br /&gt;
         };&lt;br /&gt;
&lt;br /&gt;
        my $cloudk = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
        if ($cloudk ne 0) {&lt;br /&gt;
          my $cloudk_base = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_cloudk_base&amp;quot;,0) ;&lt;br /&gt;
#          printf &amp;quot;cloudk &amp;quot;.$cloudk.&amp;quot; &amp;quot;.$cloudk_base.&amp;quot;\n&amp;quot; ;&lt;br /&gt;
          $Solar_Correction_Cloud = round((1 + ($Solar_Cloud - $cloudk_base) * $cloudk / 100),3) ;&lt;br /&gt;
        } else {&lt;br /&gt;
          $Solar_Correction_Cloud = 1 ;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        my $raink  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink&amp;quot;,0) * -0.01 ;&lt;br /&gt;
        if ($raink ne 0) {&lt;br /&gt;
          my $raink_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_raink_base&amp;quot; ,0) ;&lt;br /&gt;
#          printf &amp;quot;raink  &amp;quot;.$raink.&amp;quot; &amp;quot;.$raink_base.&amp;quot;\n&amp;quot; ;&lt;br /&gt;
          $Solar_Correction_Rain = round((1 + ($Solar_Rain  - $raink_base ) * $raink  / 100),3) ;&lt;br /&gt;
        } else {&lt;br /&gt;
          $Solar_Correction_Rain = 1 ;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        my $tempk  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk&amp;quot;,0) * -0.01 ;&lt;br /&gt;
        if ($tempk ne 0) {&lt;br /&gt;
          my $tempk_base  = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_tempk_base&amp;quot; ,0) ;&lt;br /&gt;
#          printf &amp;quot;tempk  &amp;quot;.$tempk.&amp;quot; &amp;quot;.$tempk_base.&amp;quot;\n&amp;quot; ;&lt;br /&gt;
          $Solar_Correction_Temp = round((1 + ($Solar_Temp  - $tempk_base ) * $tempk  / 100),3) ;&lt;br /&gt;
        } else {&lt;br /&gt;
          $Solar_Correction_Temp = 1 ;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        my $Solar_Correction_Faktor = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;forecast_factor&amp;quot;,1) ;&lt;br /&gt;
&lt;br /&gt;
        my $module_1_count = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_1_count&amp;quot;,0) ;&lt;br /&gt;
        if ($module_1_count ne 0) {&lt;br /&gt;
          $Solar_1 =  $module_1_count * ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_1_power&amp;quot;,1)/1000 ;&lt;br /&gt;
          $Solar_1 =  $Solar_1 * Solar_plain(ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_1_plain&amp;quot;,0) , ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_1_direction&amp;quot;,0) , $timestamp) ;&lt;br /&gt;
          $Solar_1 =  $Solar_1 * $Solar_SolarRadiation ;&lt;br /&gt;
          $Solar_1 =  $Solar_1 * $Solar_Correction_Temp * $Solar_Correction_Cloud * $Solar_Correction_Rain * $Solar_Correction_Faktor ;&lt;br /&gt;
          $Solar_1 =  ($Solar_1 lt 0)?0:round($Solar_1,0) ;&lt;br /&gt;
        } else {&lt;br /&gt;
          $Solar_1 = 0 ;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        my $module_2_count = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_2_count&amp;quot;,0) ;&lt;br /&gt;
        if ($module_2_count ne 0) {&lt;br /&gt;
          $Solar_2 =  $module_2_count * ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_2_power&amp;quot;,1)/1000 ;&lt;br /&gt;
          $Solar_2 =  $Solar_2 * Solar_plain(ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_2_plain&amp;quot;,0) , ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_2_direction&amp;quot;,0) , $timestamp) ;&lt;br /&gt;
          $Solar_2 =  $Solar_2 * $Solar_SolarRadiation ;&lt;br /&gt;
          $Solar_2 =  $Solar_2 * $Solar_Correction_Temp * $Solar_Correction_Cloud * $Solar_Correction_Rain * $Solar_Correction_Faktor ;&lt;br /&gt;
          $Solar_2 =  ($Solar_2 lt 0)?0:round($Solar_2,0) ;&lt;br /&gt;
        } else {&lt;br /&gt;
          $Solar_2 = 0 ;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        my $module_3_count = ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_1_count&amp;quot;,0) ;&lt;br /&gt;
        if ($module_3_count ne 0) {&lt;br /&gt;
          $Solar_3 =  $module_3_count * ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_3_power&amp;quot;,1)/1000 ;&lt;br /&gt;
          $Solar_3 =  $Solar_3 * Solar_plain(ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_3_plain&amp;quot;,0) , ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_3_direction&amp;quot;,0) , $timestamp) ;&lt;br /&gt;
          $Solar_3 =  $Solar_3 * $Solar_SolarRadiation ;&lt;br /&gt;
          $Solar_3 =  $Solar_3 * $Solar_Correction_Temp * $Solar_Correction_Cloud * $Solar_Correction_Rain * $Solar_Correction_Faktor ;&lt;br /&gt;
          $Solar_3 =  ($Solar_3 lt 0)?0:round($Solar_3,0) ;&lt;br /&gt;
        } else {&lt;br /&gt;
          $Solar_3 = 0 ;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        $logentry = round( $Solar_1 + $Solar_2 + $Solar_3,0) ;&lt;br /&gt;
&lt;br /&gt;
#        printf $fc.&amp;quot; &amp;quot;.$hour.&amp;quot; &amp;quot;.$Solar_SolarRadiation.&amp;quot; &amp;quot;.$logentry.&amp;quot;\n&amp;quot; ;&lt;br /&gt;
&lt;br /&gt;
        if ($fc == 0 and $hour == $i and $orientation eq &amp;quot;ESW&amp;quot;) {&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_SolarRadiation &amp;quot;.$Solar_SolarRadiation ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Cloud &amp;quot;.$Solar_Cloud ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Rain &amp;quot;.$Solar_Rain ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Correction_Cloud &amp;quot;.$Solar_Correction_Cloud ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Correction_Rain &amp;quot;.$Solar_Correction_Rain ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Correction_Temp &amp;quot;.$Solar_Correction_Temp ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_Calculation &amp;quot;.$logentry ;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_1_name&amp;quot;,0).&amp;quot; &amp;quot;.$Solar_1;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_2_name&amp;quot;,0).&amp;quot; &amp;quot;.$Solar_2;&lt;br /&gt;
          fhem &amp;quot;setreading &amp;quot;.$logdevice.&amp;quot; Solar_&amp;quot;.ReadingsVal($logdevice.&amp;quot;_config&amp;quot;,&amp;quot;module_3_name&amp;quot;,0).&amp;quot; &amp;quot;.$Solar_3;&lt;br /&gt;
         } ;&lt;br /&gt;
        if ($fc != 0) {&lt;br /&gt;
          fhem &amp;quot;set &amp;quot;.$logdb.&amp;quot; addCacheLine &amp;quot;.$timestamp.&amp;quot;|&amp;quot;.$logdevice.&amp;quot;|addlog|&amp;quot;.$reading.&amp;quot;: &amp;quot;.$logentry.&amp;quot;|&amp;quot;.$reading.&amp;quot;|&amp;quot;.$logentry.&amp;quot;|&amp;quot;;&lt;br /&gt;
         } ;&lt;br /&gt;
       } ;&lt;br /&gt;
&lt;br /&gt;
    return (0);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== Solar_Plain ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub Solar_plain($$$) {&lt;br /&gt;
&lt;br /&gt;
        my $angle       = $_[0];&lt;br /&gt;
        my $orienta     = $_[1];&lt;br /&gt;
        my $time        = $_[2];&lt;br /&gt;
        my $azimuth     = fhem &amp;quot;get Astro text SunAz &amp;quot;.$time ;&lt;br /&gt;
&lt;br /&gt;
# angles in radiant&lt;br /&gt;
        my $rad         = 57.296;&lt;br /&gt;
        my $elevation   = fhem &amp;quot;get Astro text SunAlt &amp;quot;.$time ;&lt;br /&gt;
           $elevation   = $elevation / $rad;&lt;br /&gt;
        $angle          = $angle     / $rad;&lt;br /&gt;
        my $orientation = ($azimuth - 180 - $orienta) / $rad;&lt;br /&gt;
&lt;br /&gt;
#  avoid unrealistic values (normally formula should only be used within boundaries of orientation +/- 90 degrees)&lt;br /&gt;
        return (0.001) if ($elevation &amp;lt;= 0.35); &lt;br /&gt;
&lt;br /&gt;
        if(cos($orientation) &amp;lt; 0.05 &amp;amp;&amp;amp; cos($orientation) &amp;gt; -0.2) {$orientation =$orientation - 0.2}&lt;br /&gt;
&lt;br /&gt;
##    Log3 &amp;quot;&amp;quot;, 1, &amp;quot;Solar radiation, azimuth = $azimuth, orientation=$orientation, elevation=$elevation, angle=$angle&amp;quot;;&lt;br /&gt;
     my $factor = sin($angle) /&lt;br /&gt;
         (sin( $elevation) / &lt;br /&gt;
          cos( $elevation)) * &lt;br /&gt;
        cos($orientation) +&lt;br /&gt;
                cos($angle);&lt;br /&gt;
&lt;br /&gt;
# otherwise too big values (normally formula should only be used within boundaries of orientation +/- 90 degrees)&lt;br /&gt;
    if ($factor &amp;gt; - 0.05 &amp;amp;&amp;amp; $factor &amp;lt; 0.05) {$factor = 0.05}&lt;br /&gt;
&lt;br /&gt;
    return ($factor);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== wunderground ===&lt;br /&gt;
Diesen Dienst nutze ich nicht für die Prognose, jedoch kann man dort private Wetterstationen in seinem näheren Umfeld finden, die die Sonneneinstrahlung und den UV Index messen. Das ist dann als aktueller Wert in den Diagrammen zu sehen und lässt aktuelle Beschattung durch Wolken erkennen. Hier kann man dann auch mehrere Stationen definieren und eventuell mit einem Durchschnitt arbeiten, wenn nicht gerade der Nachbar eine Station hat.&lt;br /&gt;
Für diese Abfrage ist keine Registrierung notwendig und man muss auch nicht selber mir einer Station Daten liefern.&lt;br /&gt;
Aber bitte, die Abfrage nicht in einem zu kurzen Abstand, also mit hoher Frequenz stellen! Hier wird alle 15 Minuten (900 Sekunden) abgefragt.&lt;br /&gt;
=== RAW Definition Wetter_&amp;lt;Wohnort&amp;gt; ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod wetter_&amp;lt;Wohnort&amp;gt; HTTPMOD https://www.wunderground.com/dashboard/pws/&amp;lt;Wohnort_Station&amp;gt; 900&lt;br /&gt;
&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogExclude .*&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; DbLogInclude solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; alias wetter_&amp;lt;Wohnort&amp;gt;&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; enableControlSet 1&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; event-on-change-reading solarRadiation,solarUV,temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; group ASC Environment&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; icon weather_sunrise&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Name date&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading01Regex Summary.*&amp;gt;([[:alpha:]]{1,8} [\d]{1,2}, [\d]{4})&amp;lt;.*Temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Name dewpointTemperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading02Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;.*HUMIDITY&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Name dewpointTemperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading03Regex DEWPOINT.*&amp;gt;([\d\.]+)&amp;lt;.*HUMIDITY&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Name humidity&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading04Regex HUMIDITY.*&amp;gt;([\d\.]+)&amp;lt;.*WIND&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Name precip1hrmetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading05Regex PRECIP RATE.*&amp;gt;([\d\.]+)&amp;lt;.*PRECIP TOTAL&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Name preciptodaymetric&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading06Regex PRECIP TOTAL.*&amp;gt;([\d\.]+)&amp;lt;.*tile-precipitation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Name pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07OExpr UConv::inhg2hpa($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading07Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Format %.2f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Name pressure_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading08Regex CURRENT.*&amp;gt;([\d\.]+)&amp;lt;.*tile-pressure&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Name solarRadiation&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading09Regex SOLAR RADIATION.*CURRENT.*weather__text&amp;quot;&amp;gt;([\d\.]+)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Name solarUV&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading10Regex CURRENT UV.*&amp;gt;([\d\.]+)&amp;lt;.*UV RISK&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Name temperature&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading11Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Name temperature_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading12Regex current-temp.*&amp;quot;&amp;gt;([- ]*[\d\.]+).*DEWPOINT&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Name windChill&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13OExpr UConv::f2c($val,2)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading13Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Format %.1f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Name windChill_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading14Regex Feels Like.*&amp;gt;([\d\.]+)&amp;lt;.*wind-dial__container&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Name windDirection&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15OExpr UConv::compasspoint2compasspoint($val,&amp;quot;en&amp;quot;,1,&amp;quot;de&amp;quot;)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading15Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Name windDirection_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading16Regex WIND FROM.*&amp;gt;([NESW]+)&amp;lt;.*GUST&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Format %.0f&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Name windSpeed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading17Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Name windSpeed_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading18Regex wind-dial__container.*&amp;gt;([\d\.]+)&amp;lt;.*unit-speed&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Name windGust&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19OExpr UConv::mph2kph($val,1)&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading19Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Name windGust_EN&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; reading20Regex GUST.*&amp;gt;([\d\.]+)&amp;lt;.*mph&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; room Informationen-&amp;gt;Wetter,Rollos&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; sortby 03&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; stateFormat T: temperature °C | F: humidity % | W: windSpeed km/h | D: pressure hPa | U: solarUV | R: solarRadiation W/m²&lt;br /&gt;
attr wetter_&amp;lt;Wohnort&amp;gt; timeout 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Diagramme ==&lt;br /&gt;
=== RAW Definition Hauptverbraucher ===&lt;br /&gt;
[[Bild:Plenticore_Hauptverbraucher.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_2 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_2 SVG LogDB:SVG_LogDB_Photovoltaik_2:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_2 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_2.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-03-16 10:23:52&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Hauptverbraucher&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB PV_Anlage_1:Total_DC_Power:::$val=abs($val)&lt;br /&gt;
#LogDB PV_Anlage_1:Total_PV_Power_reserve::&lt;br /&gt;
#LogDB StromZaehler_Heizung:SMAEM1901401955_Saldo_Wirkleistung:::$val=abs($val)&lt;br /&gt;
#LogDB shelly02:Power_0::&lt;br /&gt;
#LogDB shelly03:Power::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC&#039; ls l1 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_PV_reserve&#039; ls l2 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Heizung&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Pool&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Waschmaschine&#039; ls l3 lw 1 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== RAW Definition Leistungsbezug ===&lt;br /&gt;
[[Bild:Plenticore_Leistungsbezug.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_3 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_3 SVG LogDB:SVG_LogDB_Photovoltaik_3:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 room Strom-&amp;gt;Info,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_3 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_3.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-07-22 13:51:57&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Leistungsbezug&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;&amp;quot;&lt;br /&gt;
set yrange [0:9500]&lt;br /&gt;
set y2range [0:9500]&lt;br /&gt;
&lt;br /&gt;
#LogDB PV_Anlage_1:Total_DC_Power:::$val=abs($val)&lt;br /&gt;
#LogDB PV_Anlage_1:Home_own_consumption_from_PV::&lt;br /&gt;
#LogDB PV_Anlage_1:Home_own_consumption_from_battery::&lt;br /&gt;
#LogDB PV_Anlage_1:Home_own_consumption_from_grid::&lt;br /&gt;
#LogDB PV_Anlage_1:Actual_battery_charge_usable_Power::&lt;br /&gt;
#LogDB PV_Anlage_1:Total_DC_Power_Max::&lt;br /&gt;
#LogDB PV_Anlage_1:Battery_temperature:::$val=$val*100&lt;br /&gt;
#LogDB Heizung:heatSourceIN:::$val=$val*100&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Power&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;own_PV&#039; ls l2fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_use&#039; ls l0fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Grid_use&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_usable&#039; ls l4 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Total_DC_Max&#039; ls l6 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Bat_Temp_Trend&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Out_Temp_Trend&#039; ls l2 lw 2 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== RAW Definition PV_Bilanz ===&lt;br /&gt;
==== SVG_LogDB_PV_Bilanz ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_PV_Bilanz SVG LogDB:SVG_LogDB_PV_Bilanz:HISTORY&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz alias SVG_LogDB_PV_Bilanz&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz fixedrange year&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_PV_Bilanz room Strom-&amp;gt;Energie&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_PV_Bilanz.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-02 09:55:06&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;PV_Bilanz&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid ytics&lt;br /&gt;
set ylabel &amp;quot;KWh&amp;quot;&lt;br /&gt;
set y2label &amp;quot;KWh&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#LogDB Dum.Energy:max_month_PVMonth::&lt;br /&gt;
#LogDB Dum.Energy:diff_week_PVMonth::&lt;br /&gt;
#LogDB Dum.Energy:max_month_PVTotalMonth::&lt;br /&gt;
#LogDB Dum.Energy:diff_week_PVTotalMonth::&lt;br /&gt;
#LogDB Dum.Energy:AutarkyQuoteYear::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;PV-Bezug-Monat&#039; ls l2fill lw 1 with bars,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;PV-Bezug-Woche&#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;PV-Total-Monat&#039; ls l1dot lw 4 with fsteps,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;PV-Total-Woche&#039; ls l1fill lw 1 with fsteps,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;AutarkyQuoteYear&#039; ls l0 lw 1 with steps&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== RAW Definition Forecast / Calculation ===&lt;br /&gt;
[[Bild:Plenticore_Forecast.png|mini|600px|rechts|]]&lt;br /&gt;
==== SVG_LogDB_Photovoltaik_4 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod SVG_LogDB_Photovoltaik_4 SVG LogDB:SVG_LogDB_Photovoltaik_4:HISTORY&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 DbLogExclude .*&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 group PV Eigenverbrauch&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 plotsize 1400,320&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr SVG_LogDB_Photovoltaik_4 sortby 00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== GPLOTFILE SVG_LogDB_Photovoltaik_4.gplot ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Created by FHEM/98_SVG.pm, 2020-08-17 08:58:42&lt;br /&gt;
set terminal png transparent size &amp;lt;SIZE&amp;gt; crop&lt;br /&gt;
set output &#039;&amp;lt;OUT&amp;gt;.png&#039;&lt;br /&gt;
set xdata time&lt;br /&gt;
set timefmt &amp;quot;%Y-%m-%d_%H:%M:%S&amp;quot;&lt;br /&gt;
set xlabel &amp;quot; &amp;quot;&lt;br /&gt;
set title &#039;Forecast / Calculation&#039;&lt;br /&gt;
set ytics &lt;br /&gt;
set y2tics &lt;br /&gt;
set grid&lt;br /&gt;
set ylabel &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set y2label &amp;quot;Leistung&amp;quot;&lt;br /&gt;
set yrange [0:10000]&lt;br /&gt;
set y2range [0:10000]&lt;br /&gt;
&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=($val&amp;gt;0?$val*50+7000:7000)&lt;br /&gt;
#LogDB wetter_wolfskehlen_II:solarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_SolarRadiation:::$val=($val&amp;gt;0?$val*3+7000:7000)&lt;br /&gt;
#LogDB Astro:SunAlt:::$val=7000&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_Calculation_fc1::&lt;br /&gt;
#LogDB PV_Anlage_1:Power_DC_Sum::&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_Calculation::&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_East::&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_South::&lt;br /&gt;
#LogDB PV_Anlage_1:Solar_West::&lt;br /&gt;
&lt;br /&gt;
plot &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Sonnenhöhe&#039; ls l7 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiation&#039; ls l8 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;SolarRadiationPrognose&#039; ls l8 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;70%&#039; ls l0 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation_fc1&#039; ls l0 lw 2 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Power_DC_Sum&#039; ls l1fill lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;Calculation&#039; ls l5 lw 1 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;East&#039; ls l2 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;South&#039; ls l3 lw 0.5 with lines,\&lt;br /&gt;
     &amp;quot;&amp;lt;IN&amp;gt;&amp;quot; using 1:2 axes x1y2 title &#039;West&#039; ls l4 lw 0.5 with lines&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
== PV Eigenverbrauch-Steuerung ==&lt;br /&gt;
=== Beispiel Luft Wärme Pumpe ===&lt;br /&gt;
==== RAW Definition LWP_LuftWärmePumpe (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LWP dummy&lt;br /&gt;
attr LWP DbLogExclude .*&lt;br /&gt;
attr LWP DbLogInclude state&lt;br /&gt;
attr LWP alias LWP_LuftWärmePumpe&lt;br /&gt;
attr LWP group PV Eigenverbrauch&lt;br /&gt;
attr LWP icon sani_earth_source_heat_pump&lt;br /&gt;
attr LWP readingList LWP_Button PowerLevelMinTime PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr LWP room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP setList LWP_Button:uzsuToggle,on,off PowerLevelMinTime:slider,60,30,300 PowerLimitOn:slider,1000,250,4000 PowerLimitOff:slider,1000,250,4000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,900,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr LWP sortby 05&lt;br /&gt;
attr LWP stateFormat state&lt;br /&gt;
attr LWP verbose 0&lt;br /&gt;
attr LWP webCmd LWP_Button&lt;br /&gt;
&lt;br /&gt;
setstate LWP off&lt;br /&gt;
setstate LWP 2020-08-05 17:38:03 LWP_Button off&lt;br /&gt;
setstate LWP 2020-03-02 11:56:45 PowerLevelMinTime 600&lt;br /&gt;
setstate LWP 2020-02-05 14:11:42 PowerLimitOff 2250&lt;br /&gt;
setstate LWP 2020-03-02 11:56:39 PowerLimitOn 3000&lt;br /&gt;
setstate LWP 2019-08-02 10:31:21 RunTimeMin 3600&lt;br /&gt;
setstate LWP 2020-02-05 14:13:01 RunTimePerDay 28800&lt;br /&gt;
setstate LWP 2019-12-29 10:47:55 SetCmdOff set shelly01 off 0&lt;br /&gt;
setstate LWP 2019-07-22 15:35:59 SetCmdOn set shelly01 on 0&lt;br /&gt;
setstate LWP 2019-11-09 12:13:04 TimeEnd 16:00&lt;br /&gt;
setstate LWP 2020-04-02 13:51:54 TimeStart 12:30&lt;br /&gt;
setstate LWP 2020-08-05 17:38:03 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod LWP_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
    ([LWP_Counter:pulseTimePerDay] &amp;gt;= [LWP:RunTimePerDay] and\&lt;br /&gt;
     [LWP_Counter:pulseTimeIncrement] &amp;gt;= [LWP:RunTimeMin] and\&lt;br /&gt;
     [LWP:state] ne &amp;quot;off&amp;quot; and [LWP:LWP_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot; LWP_PV cmd_1 PV : LWP off&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 50.0&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
  ( ([PV_Anlage_1:Total_PV_Power_reserve]+[StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung]) &amp;lt; [LWP:PowerLimitOff] and\&lt;br /&gt;
     [LWP_Counter:pulseTimeIncrement] &amp;gt;= [LWP:RunTimeMin] and\&lt;br /&gt;
     [LWP:state] ne &amp;quot;off&amp;quot; and\&lt;br /&gt;
     [LWP:LWP_Button] ne &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot; LWP_PV cmd_2 PV : LWP off&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 50.0&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außerkraft,\&lt;br /&gt;
##   wenn wärend der Wartezeit die PV Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [LWP:PowerLimitOff] and\&lt;br /&gt;
     [LWP_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
     [LWP_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
     [LWP:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_3 PV : Stop wait timer LWP&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch einschalten: wenn PV Produktion über dem Mindestbedarf ist und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([Astro:ObsSeason] ne &amp;quot;Sommer&amp;quot; and [Astro:ObsSeason] ne &amp;quot;Frühling&amp;quot; and\&lt;br /&gt;
     [PV_Anlage_1:Total_PV_Power_reserve] &amp;gt;= [LWP:PowerLimitOn] and\&lt;br /&gt;
     [[LWP:TimeStart]-[LWP:TimeEnd]] and\&lt;br /&gt;
     [LWP:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
     [LWP_Counter:pulseTimePerDay] &amp;lt; [LWP:RunTimePerDay] and\&lt;br /&gt;
     [Heizung:hotWaterTemperature] &amp;lt; 60 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_4 : LWP on&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP on&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 60.0&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Signal für den PV-Modus der LWP einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([LWP:LWP_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_5 PV : LWP on for manuel PV-Modus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP on&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 60.0&amp;quot;)}\&lt;br /&gt;
     )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Signal für den PV-Modus der LWP abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([LWP:LWP_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
     [$SELF:cmd_nr] eq &amp;quot;5&amp;quot;  )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_6 PV : LWP off after manuel PV-Modus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 50.0&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Stop wait Timer für das Abschalten, wenn die LWP beim Starten noch anläuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
   ([StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;gt; 300 and\&lt;br /&gt;
    [Heizung:opStateHeatPump1] eq &amp;quot;Wärmepumpe kommt&amp;quot; and\&lt;br /&gt;
    [Heizung:opStateHeatPump3] eq &amp;quot;Pumpenvorlauf&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
     ({Log 3, &amp;quot;LWP_PV cmd_7 : Stop wait timer LWP&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 LWP Ende\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
   ([StromZaehler_Heizung:SMAEM1901401955_Bezug_Wirkleistung] &amp;lt; 300 and\&lt;br /&gt;
    [LWP_Counter:pulseTimeIncrement] &amp;gt;= [LWP:RunTimeMin] and\&lt;br /&gt;
    ([Heizung:opStateHeatPump1] ne &amp;quot;Wärmepumpe läuft&amp;quot; or [Heizung:opStateHeatPump3] eq &amp;quot;Luftabtauen&amp;quot; ) and\&lt;br /&gt;
    ([$SELF:cmd_nr] eq &amp;quot;4&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;10&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_8 : LWP run finished&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;LWP&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget 50.0&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading LWP LWP_Button off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 LWP Zwangseinschalten: Sollte das Brauchwasser noch nicht aufgeheizt sein, wird um die Hysterese erhöht.\&lt;br /&gt;
##   Dies kann passieren, wenn am Tag vorher der PV-Modus lief und dann das Wasser noch knapp über dem Mindestwert ist.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
   ([Astro:ObsSeason] ne &amp;quot;Sommer&amp;quot; and [Astro:ObsSeason] ne &amp;quot;Frühling&amp;quot; and\&lt;br /&gt;
    [[LWP:TimeEnd]] and\&lt;br /&gt;
    [Heizung:hotWaterTemperature] &amp;lt; 47 and\&lt;br /&gt;
    ([LWP_Counter:pulseTimePerDay] &amp;lt; [Pool:RunTimePerDay] or\&lt;br /&gt;
     [LWP_Counter:countsPerDay] eq 0) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_9 : LWP on for water heating&amp;quot;}\&lt;br /&gt;
\&lt;br /&gt;
     {fhem(&amp;quot;set Heizung hotWaterTemperatureTarget &amp;quot;. (ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperature&amp;quot;,46)+4))}\&lt;br /&gt;
\&lt;br /&gt;
     {Log 3, &amp;quot;LWP_PV cmd_9 : LWP hotWaterTemperatureTarget &amp;quot;.ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;hotWaterTemperatureTarget&amp;quot;,0)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 10 Hohe Priorität im Winter fuer die LWP\&lt;br /&gt;
##    Einschalten, wenn der Pool läuft, der Speicher geladen ist und noch Überschuss da ist.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
    ([Astro:ObsSeason] eq &amp;quot;Winter&amp;quot; and\&lt;br /&gt;
     [PV_Anlage_1:Total_PV_Power_reserve] &amp;gt;= 2000 and\&lt;br /&gt;
     [shelly02:power_0] &amp;gt; 800 and\&lt;br /&gt;
     [PV_Anlage_1:Act_state_of_charge] &amp;gt; 60 and\&lt;br /&gt;
     [Heizung:hotWaterTemperature] &amp;lt; 60 and \&lt;br /&gt;
     [$SELF:cmd_nr] ne &amp;quot;10&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;LWP_PV cmd_10 : LWP Priorität&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;set LWP_PV cmd_4&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
&lt;br /&gt;
attr LWP_PV DbLogExclude .*&lt;br /&gt;
attr LWP_PV DbLogInclude state,cmd.*,Device,LWP_Status,wait_timer&lt;br /&gt;
attr LWP_PV alias LWP_PV&lt;br /&gt;
attr LWP_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch aus|Stop wait timer|Eigenverbrauch ein|LWP ein für manuellen PV-Modus|LWP aus nach manuellem PV-Modus|Stop wait timer fuer aus|LWP aus nach PV-Modus|LWP Brauchwasser nachheizen|LWP Priorität&lt;br /&gt;
attr LWP_PV do always&lt;br /&gt;
attr LWP_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_PV icon sani_earth_source_heat_pump&lt;br /&gt;
attr LWP_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_PV sortby 01&lt;br /&gt;
attr LWP_PV stateFormat state : LWP_Status : Brauchwasser e_Heizung_hotWaterTemperature °C&lt;br /&gt;
attr LWP_PV userReadings LWP_Status { ReadingsVal(&amp;quot;Heizung&amp;quot;,&amp;quot;state&amp;quot;,&amp;quot;&amp;quot;) }&lt;br /&gt;
attr LWP_PV verbose 5&lt;br /&gt;
attr LWP_PV wait 0:10:0:[LWP:PowerLevelMinTime]:0:0:900:0:0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
- RAW Definition LWP_Signale (Shelly Modul: shelly1pm)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly01 Shelly 192.168.178.55&lt;br /&gt;
attr shelly01 DbLogExclude .*&lt;br /&gt;
attr shelly01 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly01 alias LWP_Signale&lt;br /&gt;
attr shelly01 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly01 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly01 icon taster_ch_1&lt;br /&gt;
attr shelly01 mode relay&lt;br /&gt;
attr shelly01 model shelly1pm&lt;br /&gt;
attr shelly01 room Shelly,Heizung-&amp;gt;System,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly01 sortby 02&lt;br /&gt;
attr shelly01 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;power&amp;quot;,0),\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly01 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly01 webCmd |&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== RAW Definition LWP_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defmod LWP_Counter HourCounter LWP:on.* LWP:off&lt;br /&gt;
attr LWP_Counter DbLogExclude .*&lt;br /&gt;
attr LWP_Counter alias LWP_Counter&lt;br /&gt;
attr LWP_Counter event-min-interval .*:600&lt;br /&gt;
attr LWP_Counter event-on-change-reading .*&lt;br /&gt;
attr LWP_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr LWP_Counter icon time_timer&lt;br /&gt;
attr LWP_Counter interval 5&lt;br /&gt;
attr LWP_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr LWP_Counter sortby 03&lt;br /&gt;
attr LWP_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition rg_LWP_Status (readingsGroup Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod rg_LWP_Status readingsGroup &amp;lt;Device&amp;gt;,&amp;lt;Information&amp;gt;,&amp;lt;Wert&amp;gt; LWP:&amp;lt;Status&amp;gt;,state LWP:&amp;lt;PowerLevelMinTime&amp;gt;,PowerLevelMinTime LWP:&amp;lt;PowerLimitOn&amp;gt;,PowerLimitOn LWP:&amp;lt;PowerLimitOff&amp;gt;,PowerLimitOff LWP:&amp;lt;TimeStart&amp;gt;,!TimeStart LWP:&amp;lt;TimeEnd&amp;gt;,!TimeEnd LWP:&amp;lt;RunTimeMin&amp;gt;,RunTimeMin LWP_Counter:&amp;lt;RunTimeMin&amp;gt;,pulseTimeIncrement LWP:&amp;lt;RunTimePerDay&amp;gt;,RunTimePerDay LWP_Counter:&amp;lt;RunTimePerDay&amp;gt;,pulseTimePerDay LWP_PV:&amp;lt;wait&amp;gt;,wait_timer LWP_PV:&amp;lt;TimeStart&amp;gt;,timer_01_c04 LWP_PV:&amp;lt;TimeEnd&amp;gt;,timer_02_c04&lt;br /&gt;
attr rg_LWP_Status DbLogExclude .*&lt;br /&gt;
attr rg_LWP_Status alias Status LuftWärmePumpe Eigenverbrauch&lt;br /&gt;
attr rg_LWP_Status commands {state  =&amp;gt; &#039;state:on,off&#039;,\&lt;br /&gt;
PowerLevelMinTime =&amp;gt; &#039;PowerLevelMinTime:selectnumbers,60,60,600,0,lin&#039;,\&lt;br /&gt;
PowerLimitOn =&amp;gt; &#039;PowerLimitOn:selectnumbers,1000,250,4000,0,lin&#039;,\&lt;br /&gt;
PowerLimitOff =&amp;gt; &#039;PowerLimitOff:selectnumbers,1000,250,4000,0,lin&#039;,\&lt;br /&gt;
RunTimeMin =&amp;gt; &#039;RunTimeMin:selectnumbers,300,300,14400,0,lin&#039;,\&lt;br /&gt;
RunTimePerDay =&amp;gt; &#039;RunTimePerDay:selectnumbers,300,300,28800,0,lin&#039;,\&lt;br /&gt;
TimeStart =&amp;gt; &#039;TimeStart:time&#039;,\&lt;br /&gt;
TimeEnd =&amp;gt; &#039;TimeEnd:time&#039;}&lt;br /&gt;
attr rg_LWP_Status group PV Status&lt;br /&gt;
attr rg_LWP_Status nameStyle style=&amp;quot;color:grey&amp;quot;&lt;br /&gt;
attr rg_LWP_Status room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr rg_LWP_Status sortby 01&lt;br /&gt;
attr rg_LWP_Status style style=&amp;quot;font-size:18px&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Pool===&lt;br /&gt;
==== RAW Definition Pool_Softube (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool dummy&lt;br /&gt;
attr Pool DbLogExclude .*&lt;br /&gt;
attr Pool DbLogInclude state&lt;br /&gt;
attr Pool alias Pool_Softube&lt;br /&gt;
attr Pool event-on-change-reading .*&lt;br /&gt;
attr Pool group PV Eigenverbrauch&lt;br /&gt;
attr Pool icon scene_swimming&lt;br /&gt;
attr Pool readingList Pool_Button PowerLevelMinTime PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay RunTimePerDaySummer RunTimePerDayWinter SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Pool room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool setList Pool_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,500,100,1500 PowerLimitOff:slider,0,100,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,900,300,64800 RunTimePerDaySummer:slider,900,300,7200 RunTimePerDayWinter:slider,3600,900,64800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Pool sortby 06&lt;br /&gt;
attr Pool stateFormat state&lt;br /&gt;
attr Pool verbose 0&lt;br /&gt;
attr Pool webCmd Pool_Button&lt;br /&gt;
&lt;br /&gt;
setstate Pool off&lt;br /&gt;
setstate Pool 2020-08-28 13:30:10 Pool_Button off&lt;br /&gt;
setstate Pool 2019-12-02 10:31:26 PowerLevelMinTime 600&lt;br /&gt;
setstate Pool 2019-11-13 10:58:18 PowerLimitOff 800&lt;br /&gt;
setstate Pool 2019-11-06 11:49:00 PowerLimitOn 1000&lt;br /&gt;
setstate Pool 2020-08-14 16:26:09 RunTimeMin 1800&lt;br /&gt;
setstate Pool 2020-08-28 06:15:00 RunTimePerDay 3600&lt;br /&gt;
setstate Pool 2020-08-16 13:17:45 RunTimePerDaySummer 3600&lt;br /&gt;
setstate Pool 2020-08-25 19:32:33 RunTimePerDayWinter 14400&lt;br /&gt;
setstate Pool 2019-08-01 14:18:08 SetCmdOff set shelly02 off 0&lt;br /&gt;
setstate Pool 2019-08-02 09:33:06 SetCmdOn set shelly02 on 0&lt;br /&gt;
setstate Pool 2019-10-31 21:53:28 TimeEnd 16:00&lt;br /&gt;
setstate Pool 2020-04-08 18:19:29 TimeStart 12:30&lt;br /&gt;
setstate Pool 2020-08-28 14:13:02 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
 ([Pool_Counter:pulseTimePerDay] &amp;gt;= [Pool:RunTimePerDay] and\&lt;br /&gt;
  [Pool_Counter:pulseTimeIncrement] &amp;gt;= [Pool:RunTimeMin] and\&lt;br /&gt;
  [Pool:state] eq &amp;quot;on&amp;quot; and [Pool:Pool_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_1 : Pool off&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch abschalten: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist.\&lt;br /&gt;
##   Bei Pool Nutzung und Pflegeprogramm wird nicht abgeschaltet.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Pool:PowerLimitOff] and\&lt;br /&gt;
  [Pool_Counter:pulseTimeIncrement] &amp;gt;= [Pool:RunTimeMin] and\&lt;br /&gt;
  [Pool:state] eq &amp;quot;on&amp;quot; and \&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;10&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_2 : Pool off&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Pool Pool_Button off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4 wieder außer kraft,\&lt;br /&gt;
##   wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Pool:PowerLimitOff] and\&lt;br /&gt;
  [$SELF:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [$SELF:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Pool:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_3 : Stop wait timer Pool&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch einschalten: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist wird\&lt;br /&gt;
##    und die Laufzeit pro Tag noch nicht erreicht ist;; Bei über 7000 Watt Einspeisung sofort aktivieren\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 (([PV_Anlage_1:Total_PV_Power_reserve] &amp;gt;= [Pool:PowerLimitOn] and\&lt;br /&gt;
   [[Pool:TimeStart]-[Pool:TimeEnd]] and\&lt;br /&gt;
   [Pool:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
   [Pool_Counter:pulseTimePerDay] &amp;lt; [Pool:RunTimePerDay]\&lt;br /&gt;
  ) or\&lt;br /&gt;
  [PV_Anlage_1:Total_active_power_(powermeter)] &amp;lt;= -7000\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_4 : Pool on&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool on&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose für die Benutzung des Pools einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Pool:Pool_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_5 : Pool on for usage&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool on&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose des Pools abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Pool:Pool_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_6 : Pool off after usage&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Stop wait Timer für das Abschalten, wenn die Pumpe beim Starten noch anläuft\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly02:power_0] &amp;gt; 10 and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;9&amp;quot;) and\&lt;br /&gt;
  [$SELF:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [$SELF:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Pool:state] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_7 : Stop wait timer Pool&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Pool Ende\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly02:power_0] &amp;lt; 10 and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;9&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_8 : Pool run finished&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Pool Pool_Button off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Pflege Zwangseinschaltung: Es muss mindestens einmal pro Tag eingeschaltet werden, auch wenn kein PV Strom vorhanden war.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([[Pool:TimeEnd]] and\&lt;br /&gt;
  ([Pool_Counter:pulseTimePerDay] &amp;lt; [Pool:RunTimePerDay] or\&lt;br /&gt;
   [Pool_Counter:countsPerDay] eq 0)\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_9 : Pool on for maintanance&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool on&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 10 Pflege Zwangseinschaltung bei günstigem Strom nachts im Winter\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Astro:ObsSeason] eq &amp;quot;Winter&amp;quot; and\&lt;br /&gt;
  [Strom_Kosten:aWATTar_Trigger] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [22:00-05:00]\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_10 : Pool on for maintanance by aWATTar&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool_Counter pulseTimeIncrement 0&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool on&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 11 Abschaltung bei teurem Strom\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Astro:ObsSeason] eq &amp;quot;Winter&amp;quot; and\&lt;br /&gt;
  [Strom_Kosten:aWATTar_Trigger] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;10&amp;quot;\&lt;br /&gt;
 )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Pool_PV cmd_11 : Pool off after maintanance by aWATTar&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Pool off&amp;quot;)} )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 12 Pool durch kürzere Laufzeit abkühlen lassen\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([06:15] and [Heizung:averageAmbientTemperature])\&lt;br /&gt;
\&lt;br /&gt;
    (\&lt;br /&gt;
     { if ( [Heizung:averageAmbientTemperature] &amp;gt;= 18 )\&lt;br /&gt;
         {fhem(&amp;quot;setreading Pool RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;RunTimePerDaySummer&amp;quot;,0) )}\&lt;br /&gt;
      else \&lt;br /&gt;
         {fhem(&amp;quot;setreading Pool RunTimePerDay &amp;quot;.ReadingsVal(&amp;quot;Pool&amp;quot;,&amp;quot;RunTimePerDayWinter&amp;quot;,0) )}\&lt;br /&gt;
     },\&lt;br /&gt;
     {Log 3, &amp;quot;Pool_PV cmd_12 : Pool RunTimePerDay switched&amp;quot;}\&lt;br /&gt;
    )\&lt;br /&gt;
\&lt;br /&gt;
&lt;br /&gt;
attr Pool_PV DbLogExclude .*&lt;br /&gt;
attr Pool_PV DbLogInclude cmd.*,state,cmd.*,Device,Pool_Pumpe_Status,wait_timer&lt;br /&gt;
attr Pool_PV alias Pool_PV&lt;br /&gt;
attr Pool_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch aus|Stop wait timer|Eigenverbrauch freigegeben|Pool ein für Benutzung|Pool aus nach Benutzung|Stop wait timer für aus|Pool aus|Pflegemodus ohne PV|Strombörse ein|Strombörse aus|RunTimePerDay switched&lt;br /&gt;
attr Pool_PV disable 0&lt;br /&gt;
attr Pool_PV do always&lt;br /&gt;
attr Pool_PV event-on-change-reading .*&lt;br /&gt;
attr Pool_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_PV icon scene_swimming&lt;br /&gt;
attr Pool_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_PV sortby 11&lt;br /&gt;
attr Pool_PV stateFormat state : Pool_Pumpe_Status&lt;br /&gt;
attr Pool_PV userReadings Pool_Pumpe_Status { ReadingsVal(&amp;quot;shelly02&amp;quot;,&amp;quot;power_0&amp;quot;,0)&amp;gt;10 ? &amp;quot;Pool_Pumpe_laeuft&amp;quot; : &amp;quot;Pool_Pumpe_aus&amp;quot;}&lt;br /&gt;
attr Pool_PV verbose 0&lt;br /&gt;
attr Pool_PV wait 0:10:0:[Pool:PowerLevelMinTime]:0:0:0:300:0:300&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly02 Shelly 192.168.178.52&lt;br /&gt;
attr shelly02 DbLogExclude .*&lt;br /&gt;
attr shelly02 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly02 alias Pool_Signale&lt;br /&gt;
attr shelly02 comment relais_0 =&amp;gt; Pool limit 1000 W\&lt;br /&gt;
relail_1 =&amp;gt; Terrasse Lichterkette limit 100 W&lt;br /&gt;
attr shelly02 event-on-change-reading relay.*,power.*,energy.*,state,network&lt;br /&gt;
attr shelly02 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly02 icon taster_ch_1&lt;br /&gt;
attr shelly02 mode relay&lt;br /&gt;
attr shelly02 model shelly2.5&lt;br /&gt;
attr shelly02 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly02 sortby 12&lt;br /&gt;
attr shelly02 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    Status: %s&amp;lt;br&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;Gesamt 1: %08.2f KWh\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
    Relais 1: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;state&amp;quot;,&amp;quot;none&amp;quot;) eq &amp;quot;OK&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;OK&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;Error&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_0&amp;quot;,0)/1000,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy_1&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_0&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_0&amp;quot;,0),\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay_1&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power_1&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly02 userReadings WebLink:network { my $ip=ReadingsVal($name,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) }&lt;br /&gt;
attr shelly02 verbose 0&lt;br /&gt;
attr shelly02 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Pool_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Pool_Counter HourCounter shelly02:power_0:\s[0-9]{2,}(\.[0-9]{1,2})*$  shelly02:power_0:\s[0-9]{1}(\.[0-9]{1,2})*$&lt;br /&gt;
attr Pool_Counter DbLogExclude .*&lt;br /&gt;
attr Pool_Counter alias Pool_Counter&lt;br /&gt;
attr Pool_Counter comment On und Off des Pools werden direkt über den Shelly Stromverbrauch getriggert.&lt;br /&gt;
attr Pool_Counter event-on-change-reading .*&lt;br /&gt;
attr Pool_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Pool_Counter icon time_timer&lt;br /&gt;
attr Pool_Counter interval 5&lt;br /&gt;
attr Pool_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Pool_Counter sortby 13&lt;br /&gt;
attr Pool_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition rg_Pool_Status (readingsGroup Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod rg_Pool_Status readingsGroup &amp;lt;Device&amp;gt;,&amp;lt;Information&amp;gt;,&amp;lt;Wert&amp;gt; Pool:&amp;lt;Status&amp;gt;,!state Pool:&amp;lt;PowerLevelMinTime&amp;gt;,!PowerLevelMinTime Pool:&amp;lt;PowerLimitOn&amp;gt;,!PowerLimitOn Pool:&amp;lt;PowerLimitOff&amp;gt;,!PowerLimitOff Pool:&amp;lt;TimeStart&amp;gt;,!TimeStart Pool:&amp;lt;TimeEnd&amp;gt;,!TimeEnd Pool:&amp;lt;RunTimeMin&amp;gt;,!RunTimeMin Pool_Counter:&amp;lt;RunTimeMin&amp;gt;,!pulseTimeIncrement Pool:&amp;lt;RunTimePerDay&amp;gt;,!RunTimePerDay Pool:&amp;lt;RunTimePerDaySummer&amp;gt;,!RunTimePerDaySummer Pool:&amp;lt;RunTimePerDayWinter&amp;gt;,!RunTimePerDayWinter Pool_Counter:&amp;lt;RunTimePerDay&amp;gt;,!pulseTimePerDay Pool_PV:&amp;lt;wait&amp;gt;,wait_timer Pool_PV:&amp;lt;TimeStart&amp;gt;,timer_01_c04 Pool_PV:&amp;lt;TimeEnd&amp;gt;,timer_02_c04&lt;br /&gt;
attr rg_Pool_Status DbLogExclude .*&lt;br /&gt;
attr rg_Pool_Status alias Status Softube Pool Eigenverbrauch&lt;br /&gt;
attr rg_Pool_Status commands {state  =&amp;gt; &#039;state:on,off&#039;,\&lt;br /&gt;
PowerLevelMinTime =&amp;gt; &#039;PowerLevelMinTime:selectnumbers,60,30,600,0,lin&#039;,\&lt;br /&gt;
PowerLimitOn =&amp;gt; &#039;PowerLimitOn:selectnumbers,500,250,1500,0,lin&#039;,\&lt;br /&gt;
PowerLimitOff =&amp;gt; &#039;PowerLimitOff:selectnumbers,0,100,1000,0,lin&#039;,\&lt;br /&gt;
RunTimeMin =&amp;gt; &#039;RunTimeMin:selectnumbers,300,300,14400,0,lin&#039;,\&lt;br /&gt;
RunTimePerDaySummer =&amp;gt; &#039;RunTimePerDaySummer:selectnumbers,300,300,3600,0,lin&#039;,\&lt;br /&gt;
RunTimePerDayWinter =&amp;gt; &#039;RunTimePerDayWinter:selectnumbers,3600,900,64800,0,lin&#039;,\&lt;br /&gt;
TimeStart =&amp;gt; &#039;TimeStart:time&#039;,\&lt;br /&gt;
TimeEnd =&amp;gt; &#039;TimeEnd:time&#039;}&lt;br /&gt;
attr rg_Pool_Status group PV Status&lt;br /&gt;
attr rg_Pool_Status nameStyle style=&amp;quot;color:grey&amp;quot;&lt;br /&gt;
attr rg_Pool_Status room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr rg_Pool_Status sortby 02&lt;br /&gt;
attr rg_Pool_Status style style=&amp;quot;font-size:18px&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Beispiel Waschmaschine (mit Walzenschalter ;-) ) ===&lt;br /&gt;
==== RAW Definition Waschmaschine (dummy Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine dummy&lt;br /&gt;
attr Waschmaschine DbLogExclude .*&lt;br /&gt;
attr Waschmaschine DbLogInclude state&lt;br /&gt;
attr Waschmaschine alias Waschmaschine&lt;br /&gt;
attr Waschmaschine group PV Eigenverbrauch&lt;br /&gt;
attr Waschmaschine icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine readingList Waschmaschine_Button PowerLevelMinTime PowerPhaseUse PowerLimitOn PowerLimitOff RunTimeMin RunTimePerDay SetCmdOff SetCmdOn TimeStart TimeEnd&lt;br /&gt;
attr Waschmaschine room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine setList Waschmaschine_Button:uzsuToggle,on,off PowerLevelMinTime:slider,30,30,300 PowerLimitOn:slider,250,250,2000 PowerLimitOff:slider,0,250,1000 RunTimeMin:slider,300,300,7200 RunTimePerDay:slider,7200,300,28800 SetCmdOff SetCmdOn TimeStart:time TimeEnd:time&lt;br /&gt;
attr Waschmaschine sortby 07&lt;br /&gt;
attr Waschmaschine stateFormat state&lt;br /&gt;
attr Waschmaschine verbose 0&lt;br /&gt;
attr Waschmaschine webCmd Waschmaschine_Button&lt;br /&gt;
&lt;br /&gt;
setstate Waschmaschine off&lt;br /&gt;
setstate Waschmaschine 2019-12-02 10:29:49 PowerLevelMinTime 300&lt;br /&gt;
setstate Waschmaschine 2019-11-06 10:56:22 PowerLimitOff 250&lt;br /&gt;
setstate Waschmaschine 2020-04-20 13:06:04 PowerLimitOn 2000&lt;br /&gt;
setstate Waschmaschine 2019-12-02 15:01:18 RunTimeMin 5400&lt;br /&gt;
setstate Waschmaschine 2020-04-02 13:59:34 RunTimePerDay 19200&lt;br /&gt;
setstate Waschmaschine 2020-01-01 16:29:10 SetCmdOff set shelly03 off 0&lt;br /&gt;
setstate Waschmaschine 2020-01-01 16:29:24 SetCmdOn set shelly03 on 0&lt;br /&gt;
setstate Waschmaschine 2019-08-01 14:25:25 TimeEnd 18:00&lt;br /&gt;
setstate Waschmaschine 2019-10-28 09:13:30 TimeStart 09:00&lt;br /&gt;
setstate Waschmaschine 2020-08-27 16:17:23 Waschmaschine_Button off&lt;br /&gt;
setstate Waschmaschine 2020-08-28 16:29:42 state off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_PV (DOIF Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_PV DOIF ################################################################################################################\&lt;br /&gt;
## 1 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und Maximallaufzeit pro Tag erreicht ist\&lt;br /&gt;
##   jedoch nicht wenn manueller Betrieb aktiv ist.\&lt;br /&gt;
##\&lt;br /&gt;
 ([Waschmaschine_Counter:pulseTimePerDay] &amp;gt;= [Waschmaschine:RunTimePerDay] and\&lt;br /&gt;
  [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [Waschmaschine:RunTimeMin] and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;on&amp;quot; and [Waschmaschine:Waschmaschine_Button] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_1 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 2 Eigenverbrauch sperren: wenn Mindestlaufzeit erreicht wurde und die PV-Produktion unter dem Mindestbedarf ist\&lt;br /&gt;
##   ausser bei manuellem Einschalten und wenn das Waschprogramm bereits läuft\&lt;br /&gt;
##\&lt;br /&gt;
## ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Waschmaschine:PowerLimitOff] and\&lt;br /&gt;
##  [Waschmaschine_Counter:pulseTimeIncrement] &amp;gt;= [Waschmaschine:RunTimeMin] and\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Waschmaschine:PowerLimitOn] and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_2 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 3 Stop, wenn es nur ein kurzer Peak ist. Dieser Do Zweig setzt den wait timer vom Einschaltkommando cmd_4\&lt;br /&gt;
##    wieder außer kraft, wenn während der Wartezeit die PV-Anlage zuwenig liefert.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Waschmaschine:PowerLimitOff] and\&lt;br /&gt;
  [Waschmaschine_PV:wait_timer] ne &amp;quot;no timer&amp;quot; and\&lt;br /&gt;
  [Waschmaschine_PV:wait_timer] ne &amp;quot;&amp;quot; and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;off&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_3 : Waschmaschine stop wait timer&amp;quot;})\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 4 Eigenverbrauch freigeben: wenn PV-Produktion über dem Mindestbedarf ist und PV-Strom ins Netz eingespeist\&lt;br /&gt;
##   wird und die Laufzeit pro Tag noch nicht erreicht ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;gt; [Waschmaschine:PowerLimitOn] and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  [[Waschmaschine:TimeStart]-[Waschmaschine:TimeEnd]] and\&lt;br /&gt;
  [Waschmaschine_Counter:pulseTimePerDay] &amp;lt; [Waschmaschine:RunTimePerDay] )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_4 : Waschmaschine freigabe&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 5 Steckdose manuell für die Benutzung der Waschmaschine einschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Waschmaschine:Waschmaschine_Button] eq &amp;quot;on&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_5 : Waschmaschine manuell ein&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOn&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist eingeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine on&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 6 Steckdose der Waschmaschine manuell abschalten.\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([Waschmaschine:Waschmaschine_Button] eq &amp;quot;off&amp;quot; and\&lt;br /&gt;
  ([$SELF:cmd_nr] eq &amp;quot;5&amp;quot; or [$SELF:cmd_nr] eq &amp;quot;7&amp;quot;) )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_6 : Waschmaschine manuell aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 7 Statuswechsel wenn das Waschprogramm gestartet ist\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly03:power] &amp;gt; 0 and\&lt;br /&gt;
  [shelly03:power_Waschmaschine_avg] &amp;lt; 70 and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;7&amp;quot;)\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_7 : Waschmaschine Programm gestarted&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Waschprogramm gestartet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 8 Abschalten der Steckdose beim Waschprogramm Ende\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([shelly03:power] == 0 and\&lt;br /&gt;
  [shelly03:power_Waschmaschine_avg] &amp;gt; 0 and\&lt;br /&gt;
  [$SELF:cmd_nr] eq &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_8 : Waschmaschine aus&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine Waschmaschine_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Waschprogramm beendet&amp;quot;)}\&lt;br /&gt;
    )\&lt;br /&gt;
################################################################################################################\&lt;br /&gt;
## 9 Abschalten der Steckdose wenn die Waschmaschine nicht gebraucht wurde\&lt;br /&gt;
##\&lt;br /&gt;
DOELSEIF\&lt;br /&gt;
 ([PV_Anlage_1:Total_PV_Power_reserve] &amp;lt; [Waschmaschine:PowerLimitOn] and\&lt;br /&gt;
  [[Waschmaschine:TimeEnd]-[Waschmaschine:TimeStart]] and\&lt;br /&gt;
  [Waschmaschine:state] eq &amp;quot;on&amp;quot; and\&lt;br /&gt;
  [$SELF:cmd_nr] ne &amp;quot;5&amp;quot; and [$SELF:cmd_nr] ne &amp;quot;7&amp;quot; )\&lt;br /&gt;
\&lt;br /&gt;
    ({Log 3, &amp;quot;Waschmaschine cmd_9 : Eigenverbrauch sperren&amp;quot;}\&lt;br /&gt;
     {fhem(&amp;quot;&amp;quot;.ReadingsVal(&amp;quot;Waschmaschine&amp;quot;,&amp;quot;SetCmdOff&amp;quot;,0))}\&lt;br /&gt;
     {fhem(&amp;quot;set Waschmaschine off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine Waschmaschine_Button off&amp;quot;)}\&lt;br /&gt;
     {fhem(&amp;quot;setreading Waschmaschine_PV Waschmaschine_Status Steckdose ist ausgeschaltet&amp;quot;)}\&lt;br /&gt;
    )&lt;br /&gt;
attr Waschmaschine_PV DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_PV DbLogInclude state,STATE,cmd.*,Device,Waschmaschine_Status,wait_timer&lt;br /&gt;
attr Waschmaschine_PV alias Waschmaschine_PV&lt;br /&gt;
attr Waschmaschine_PV cmdState Maximalzeit pro Tag überschritten|Eigenverbrauch gesperrt|Stop wait timer|Eigenverbrauch freigegeben|Waschmaschine manuell ein|Waschmaschine manuell aus|Waschmaschine laeuft|Waschmaschine aus|Eigenverbrauch gesperrt&lt;br /&gt;
attr Waschmaschine_PV do always&lt;br /&gt;
attr Waschmaschine_PV group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_PV icon scene_washing_machine&lt;br /&gt;
attr Waschmaschine_PV room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_PV sortby 21&lt;br /&gt;
attr Waschmaschine_PV stateFormat state : Waschmaschine_Status&lt;br /&gt;
attr Waschmaschine_PV verbose 0&lt;br /&gt;
attr Waschmaschine_PV wait 0:0:0:[Waschmaschine:PowerLevelMinTime]:0:30:0:60:30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Signale (Shelly Modul: shelly1pm) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod shelly03 Shelly 192.168.178.54&lt;br /&gt;
attr shelly03 DbLogExclude .*&lt;br /&gt;
attr shelly03 DbLogInclude relay.*,power.*,energy.*&lt;br /&gt;
attr shelly03 alias Waschmaschine_Signale&lt;br /&gt;
attr shelly03 event-on-change-reading relay.*,power.*,energy.*,network&lt;br /&gt;
attr shelly03 group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr shelly03 icon taster_ch_1&lt;br /&gt;
attr shelly03 interval 60&lt;br /&gt;
attr shelly03 mode relay&lt;br /&gt;
attr shelly03 model shelly1pm&lt;br /&gt;
attr shelly03 room Shelly,Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr shelly03 sortby 22&lt;br /&gt;
attr shelly03 stateFormat {sprintf(&amp;quot;\&lt;br /&gt;
&amp;lt;TABLE&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;TR&amp;gt;\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;LEFT\&amp;quot; WIDTH=\&amp;quot;50\&amp;quot;&amp;gt;\&lt;br /&gt;
    WebLink: %s\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;100\&amp;quot;&amp;gt;\&lt;br /&gt;
    Gesamt 0: %08.2f KWh&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
  &amp;lt;TD VALIGN=\&amp;quot;TOP\&amp;quot; ALIGN=\&amp;quot;RIGHT\&amp;quot; WIDTH=\&amp;quot;70\&amp;quot;&amp;gt;\&lt;br /&gt;
    Relais 0: %s %06.1f Watt&amp;lt;br&amp;gt;\&lt;br /&gt;
  &amp;lt;/TD&amp;gt;\&lt;br /&gt;
&amp;lt;/TR&amp;gt;\&lt;br /&gt;
\&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;\&lt;br /&gt;
&amp;quot; ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;WebLink&amp;quot;,&amp;quot;none&amp;quot;) ,\&lt;br /&gt;
ReadingsVal($name,&amp;quot;energy&amp;quot;,0)/1000,\&lt;br /&gt;
(ReadingsVal($name,&amp;quot;relay&amp;quot;,&amp;quot;&amp;quot;) eq &amp;quot;off&amp;quot;) ? &amp;quot;&amp;lt;span style=&#039;color:#FF0000&#039;&amp;gt;off&amp;lt;/span&amp;gt;&amp;quot;:&amp;quot;&amp;lt;span style=&#039;color:#00FF00&#039;&amp;gt;on&amp;lt;/span&amp;gt;&amp;quot;,\&lt;br /&gt;
    ReadingsVal($name,&amp;quot;power&amp;quot;,0)\&lt;br /&gt;
)}&lt;br /&gt;
attr shelly03 userReadings WebLink:network { my $ip=ReadingsVal($NAME,&amp;quot;network&amp;quot;,&amp;quot;&amp;quot;);; $ip =~ s/connected to //gs;; $ip =~ s/&amp;lt;[^&amp;gt;]*&amp;gt;//gs;; return(&amp;quot;&amp;lt;html&amp;gt;&amp;lt;a href=&#039;http://&amp;quot;.$ip.&amp;quot;/&#039;&amp;gt;WEB&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;) },\&lt;br /&gt;
power_Waschmaschine_avg:power.* { movingAverage($NAME,&amp;quot;power&amp;quot;,300) }&lt;br /&gt;
attr shelly03 webCmd |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition Waschmaschine_Counter (HourCounter Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod Waschmaschine_Counter HourCounter Waschmaschine_PV:.*laeuft Waschmaschine_PV:Waschmaschine_Status:.*[beendet|ausgeschaltet]&lt;br /&gt;
attr Waschmaschine_Counter DbLogExclude .*&lt;br /&gt;
attr Waschmaschine_Counter alias Waschmaschine_Counter&lt;br /&gt;
attr Waschmaschine_Counter event-on-change-reading .*&lt;br /&gt;
attr Waschmaschine_Counter group PV Eigenverbrauch-Steuerung&lt;br /&gt;
attr Waschmaschine_Counter icon time_timer&lt;br /&gt;
attr Waschmaschine_Counter interval 5&lt;br /&gt;
attr Waschmaschine_Counter room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr Waschmaschine_Counter sortby 23&lt;br /&gt;
attr Waschmaschine_Counter verbose 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== RAW Definition rg_Waschmaschine_Status (readingsGroup Modul) ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
defmod rg_Waschmaschine_Status readingsGroup &amp;lt;Device&amp;gt;,&amp;lt;Information&amp;gt;,&amp;lt;Wert&amp;gt; Waschmaschine:&amp;lt;Status&amp;gt;,!state Waschmaschine:&amp;lt;PowerLevelMinTime&amp;gt;,!PowerLevelMinTime Waschmaschine:&amp;lt;PowerLimitOn&amp;gt;,!PowerLimitOn Waschmaschine:&amp;lt;PowerLimitOff&amp;gt;,!PowerLimitOff Waschmaschine:&amp;lt;TimeStart&amp;gt;,!TimeStart Waschmaschine:&amp;lt;TimeEnd&amp;gt;,!TimeEnd Waschmaschine:&amp;lt;RunTimeMin&amp;gt;,!RunTimeMin Waschmaschine_Counter:&amp;lt;RunTimeMin&amp;gt;,!pulseTimeIncrement Waschmaschine:&amp;lt;RunTimePerDay&amp;gt;,!RunTimePerDay Waschmaschine_Counter:&amp;lt;RunTimePerDay&amp;gt;,!pulseTimePerDay Waschmaschine_PV:&amp;lt;wait&amp;gt;,wait_timer Waschmaschine_PV:&amp;lt;TimeStart&amp;gt;,timer_01_c04 Waschmaschine_PV:&amp;lt;TimeEnd&amp;gt;,timer_02_c04&lt;br /&gt;
attr rg_Waschmaschine_Status DbLogExclude .*&lt;br /&gt;
attr rg_Waschmaschine_Status alias Status Waschmaschine Eigenverbrauch&lt;br /&gt;
attr rg_Waschmaschine_Status commands {state  =&amp;gt; &#039;state:on,off&#039;,\&lt;br /&gt;
PowerLevelMinTime =&amp;gt; &#039;PowerLevelMinTime:selectnumbers,30,30,300,0,lin&#039;,\&lt;br /&gt;
PowerLimitOn =&amp;gt; &#039;PowerLimitOn:selectnumbers,250,250,2000,0,lin&#039;,\&lt;br /&gt;
PowerLimitOff =&amp;gt; &#039;PowerLimitOff:selectnumbers,0,50,800,0,lin&#039;,\&lt;br /&gt;
RunTimeMin =&amp;gt; &#039;RunTimeMin:selectnumbers,300,300,7200,0,lin&#039;,\&lt;br /&gt;
RunTimePerDay =&amp;gt; &#039;RunTimePerDay:selectnumbers,7200,300,28800,0,lin&#039;,\&lt;br /&gt;
TimeStart =&amp;gt; &#039;TimeStart:time&#039;,\&lt;br /&gt;
TimeEnd =&amp;gt; &#039;TimeEnd:time&#039;}&lt;br /&gt;
attr rg_Waschmaschine_Status group PV Status&lt;br /&gt;
attr rg_Waschmaschine_Status nameStyle style=&amp;quot;color:grey&amp;quot;&lt;br /&gt;
attr rg_Waschmaschine_Status room Strom-&amp;gt;Photovoltaik&lt;br /&gt;
attr rg_Waschmaschine_Status sortby 03&lt;br /&gt;
attr rg_Waschmaschine_Status style style=&amp;quot;font-size:18px&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problemlösung ==&lt;br /&gt;
&lt;br /&gt;
== Projekte der FHEM-Community ==&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=102297|Message=958564}} - Photovoltaik mit Eigenverbrauch Steuerung (Kostal plenticore; EM410)&lt;br /&gt;
* {{Link2Forum|Topic=109875|Message=1038741}} - Kostal Plenticore Bilanz&lt;br /&gt;
* {{Link2Forum|Topic=108191|Message=1038741}} - Kostal Plenticore, EM410 (KSEM), BYD, Solarprognose, Forecast&lt;br /&gt;
&lt;br /&gt;
* {{Link2Forum|Topic=53584}} - Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog)&lt;br /&gt;
* {{Link2Forum|Topic=45176}} - Neue Version von HTTPMOD mit neuen Features zum Testen&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/142261-programmatischer-lesender-und-schreibender-zugriff-auf-kostal-plenticore-z-b-min/?pageNo=1/ Zugriff mit Python auf den Plenticore]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/144350-kostenlose-wetterprognose-pv-prognose-ertragsprogonse-mit-st%C3%BCndlicher-aufl%C3%B6sung/?pageNo=1/ Ertragsprognose mit DWD]&lt;br /&gt;
* [https://www.photovoltaikforum.com/thread/146383-eigenverbrauchssteuerung-verh%C3%A4lt-sich-mit-speicher-anders-als-ohne/?pageNo=1/ Eigenverbrauchssteuerung beim Plenticore]&lt;br /&gt;
* [https://github.com/kilianknoll/ Github Kilian DWD Forecast]&lt;br /&gt;
* [https://github.com/FL550/ Github FL550 DWD Forecast]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:IP Components]]&lt;br /&gt;
[[Kategorie:Other Components]]&lt;br /&gt;
[[Kategorie:Energieerzeugungsmessung]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Solar-/PV-%C3%9Cbersicht&amp;diff=33823</id>
		<title>Solar-/PV-Übersicht</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Solar-/PV-%C3%9Cbersicht&amp;diff=33823"/>
		<updated>2020-09-01T09:39:55Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Solar-/Photovoltaik-Übersicht&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
Diese Seite soll einen schnellen Einstieg in die für Solar-/Photovoltaik-Betreiber relevanten Seiten und Threads ermöglichen. Bitte bei Bedarf selbständig ergänzen.&lt;br /&gt;
&lt;br /&gt;
=Forum=&lt;br /&gt;
* [https://forum.fhem.de/index.php/board,61.0.html Solaranlangen] Themen rund um Solaranlagen zur Wärme- oder Stromgewinnung&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sowie aus dem Wiki:&lt;br /&gt;
&lt;br /&gt;
=Wechselrichter=&lt;br /&gt;
==Kostal==&lt;br /&gt;
* [https://wiki.fhem.de/wiki/KostalPiko Kostal Piko]&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Kostal_Plenticore_10_Plus Kostal Plenticore]&lt;br /&gt;
&lt;br /&gt;
==SMA==&lt;br /&gt;
* [https://wiki.fhem.de/wiki/SMAWechselrichter SMA Wechselrichter]&lt;br /&gt;
&lt;br /&gt;
==Solar Edge==&lt;br /&gt;
* [https://wiki.fhem.de/wiki/SolarEdge_SE10k Solar Edge SE10k]&lt;br /&gt;
&lt;br /&gt;
=Speicher=&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Sonnenspeicher Sonnenspeicher]&lt;br /&gt;
&lt;br /&gt;
=Monitoring/Auswertung=&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Enecsys_Monitoring_System Enecsys Monitoring System]&lt;br /&gt;
* [https://wiki.fhem.de/wiki/SunnyHomeManager SunnyHomeManager]&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Datenbankgest%C3%BCtzte_Erstellung_der_Energiebilanz_einer_SMA_PV-Anlage_mit_%C3%9Cberschusseinspeisung Datenbankgestützte Energiebilanz]&lt;br /&gt;
&lt;br /&gt;
=Angrenzende Themen=&lt;br /&gt;
* [https://wiki.fhem.de/wiki/ModbusAttr ModBus]&lt;br /&gt;
* [https://wiki.fhem.de/wiki/SMLUSB SML USB]&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* tbd&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Solar-/PV-%C3%9Cbersicht&amp;diff=33822</id>
		<title>Solar-/PV-Übersicht</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Solar-/PV-%C3%9Cbersicht&amp;diff=33822"/>
		<updated>2020-09-01T09:38:19Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: Die Seite wurde neu angelegt: „&amp;#039;&amp;#039;&amp;#039;Solar-/Photovoltaik-Übersicht&amp;#039;&amp;#039;&amp;#039;   Diese Seite soll einen schnellen Einstieg in die für Solar-/Photovoltaik-Betreiber relevanten Siten und Threads ermögl…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Solar-/Photovoltaik-Übersicht&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
Diese Seite soll einen schnellen Einstieg in die für Solar-/Photovoltaik-Betreiber relevanten Siten und Threads ermöglichen. Bitte bei Bedarf selbständig ergänzen.&lt;br /&gt;
&lt;br /&gt;
=Forum=&lt;br /&gt;
* [https://forum.fhem.de/index.php/board,61.0.html Solaranlangen] Themen rund um Solaranlagen zur Wärme- oder Stromgewinnung&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sowie aus dem Wiki:&lt;br /&gt;
&lt;br /&gt;
=Wechselrichter=&lt;br /&gt;
==Kostal==&lt;br /&gt;
* [https://wiki.fhem.de/wiki/KostalPiko Kostal Piko]&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Kostal_Plenticore_10_Plus Kostal Plenticore]&lt;br /&gt;
&lt;br /&gt;
==SMA==&lt;br /&gt;
* [https://wiki.fhem.de/wiki/SMAWechselrichter SMA Wechselrichter]&lt;br /&gt;
&lt;br /&gt;
==Solar Edge==&lt;br /&gt;
* [https://wiki.fhem.de/wiki/SolarEdge_SE10k Solar Edge SE10k]&lt;br /&gt;
&lt;br /&gt;
=Speicher=&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Sonnenspeicher Sonnenspeicher]&lt;br /&gt;
&lt;br /&gt;
=Monitoring/Auswertung=&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Enecsys_Monitoring_System Enecsys Monitoring System]&lt;br /&gt;
* [https://wiki.fhem.de/wiki/SunnyHomeManager SunnyHomeManager]&lt;br /&gt;
* [https://wiki.fhem.de/wiki/Datenbankgest%C3%BCtzte_Erstellung_der_Energiebilanz_einer_SMA_PV-Anlage_mit_%C3%9Cberschusseinspeisung Datenbankgestützte Energiebilanz]&lt;br /&gt;
&lt;br /&gt;
=Angrenzende Themen=&lt;br /&gt;
* [https://wiki.fhem.de/wiki/ModbusAttr ModBus]&lt;br /&gt;
* [https://wiki.fhem.de/wiki/SMLUSB SML USB]&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* tbd&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32514</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32514"/>
		<updated>2020-01-20T19:01:00Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Finale */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal.png|mini|600px|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|600px|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Fernbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Last but not least meine Konfiguration: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
Register-Settings:&lt;br /&gt;
&lt;br /&gt;
* Trägerfrequenz: 868.302 MHz&lt;br /&gt;
* Deviation: 25 kHz&lt;br /&gt;
* Bandwidth: 58 kHz&lt;br /&gt;
* Baudrate: 24.795 kBaud&lt;br /&gt;
* Modulation: GFSK&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ccregAll: &lt;br /&gt;
&lt;br /&gt;
ccreg 00: 0D 2E 2D 47 D3 91 3D 04 32 00 00 06 00 21 65 6F&lt;br /&gt;
ccreg 10: F9 F4 18 23 B9 40 07 00 18 14 6C 07 00 91 87 6B&lt;br /&gt;
ccreg 20: F8 56 11 EF 2D 12 1F 41 00 59 7F 3F 88 31 0B &lt;br /&gt;
&lt;br /&gt;
Configuration Register Detail (address, name, value):&lt;br /&gt;
0x00 IOCFG2   - 0x0D&lt;br /&gt;
0x01 IOCFG1   - 0x2E&lt;br /&gt;
0x02 IOCFG0   - 0x2D&lt;br /&gt;
0x03 FIFOTHR  - 0x47&lt;br /&gt;
0x04 SYNC1    - 0xD3&lt;br /&gt;
0x05 SYNC0    - 0x91&lt;br /&gt;
0x06 PKTLEN   - 0x3D&lt;br /&gt;
0x07 PKTCTRL1 - 0x04&lt;br /&gt;
0x08 PKTCTRL0 - 0x32&lt;br /&gt;
0x09 ADDR     - 0x00&lt;br /&gt;
0x0A CHANNR   - 0x00&lt;br /&gt;
0x0B FSCTRL1  - 0x06&lt;br /&gt;
0x0C FSCTRL0  - 0x00&lt;br /&gt;
0x0D FREQ2    - 0x21&lt;br /&gt;
0x0E FREQ1    - 0x65&lt;br /&gt;
0x0F FREQ0    - 0x6F&lt;br /&gt;
0x10 MDMCFG4  - 0xF9&lt;br /&gt;
0x11 MDMCFG3  - 0xF4&lt;br /&gt;
0x12 MDMCFG2  - 0x18&lt;br /&gt;
0x13 MDMCFG1  - 0x23&lt;br /&gt;
0x14 MDMCFG0  - 0xB9&lt;br /&gt;
0x15 DEVIATN  - 0x40&lt;br /&gt;
0x16 MCSM2    - 0x07&lt;br /&gt;
0x17 MCSM1    - 0x00&lt;br /&gt;
0x18 MCSM0    - 0x18&lt;br /&gt;
0x19 FOCCFG   - 0x14&lt;br /&gt;
0x1A BSCFG    - 0x6C&lt;br /&gt;
0x1B AGCCTRL2 - 0x07&lt;br /&gt;
0x1C AGCCTRL1 - 0x00&lt;br /&gt;
0x1D AGCCTRL0 - 0x91&lt;br /&gt;
0x1E WOREVT1  - 0x87&lt;br /&gt;
0x1F WOREVT0  - 0x6B&lt;br /&gt;
0x20 WORCTRL  - 0xF8&lt;br /&gt;
0x21 FREND1   - 0x56&lt;br /&gt;
0x22 FREND0   - 0x11&lt;br /&gt;
0x23 FSCAL3   - 0xEF&lt;br /&gt;
0x24 FSCAL2   - 0x2D&lt;br /&gt;
0x25 FSCAL1   - 0x12&lt;br /&gt;
0x26 FSCAL0   - 0x1F&lt;br /&gt;
0x27 RCCTRL1  - 0x41&lt;br /&gt;
0x28 RCCTRL0  - 0x00&lt;br /&gt;
0x29 FSTEST   - 0x59&lt;br /&gt;
0x2A PTEST    - 0x7F&lt;br /&gt;
0x2B AGCTEST  - 0x3F&lt;br /&gt;
0x2C TEST2    - 0x88&lt;br /&gt;
0x2D TEST1    - 0x31&lt;br /&gt;
0x2E TEST0    - 0x0B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Finale ===&lt;br /&gt;
&lt;br /&gt;
Nach Aktivierung der vormals ausgeschalteten Message-Typen im SIGNALduino werden nunmehr SD_Keeloq-Devices angelegt.&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino erkennt &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 2020.01.12 14:33:03 4: mySIGNALduino: Parse_MS, Decoded matched MS Protocol id 88 dmsg P88#74D21B18008B48058 length 68  RSSI = -32&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: Dispatch, P88#74D21B18008B48058, test ungleich: disabled&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: Dispatch, P88#74D21B18008B48058, -32 dB, dispatch&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: dispatch P88#74D21B18008B48058&lt;br /&gt;
 2020.01.12 14:33:04 2: mySIGNALduino: SD_Keeloq_Parse Unknown device unknown with Code 012D100 detected, please define (rawdate=74D21B18008B48058)&lt;br /&gt;
 2020.01.12 14:33:04 2: autocreate: define SD_Keeloq_012D100 SD_Keeloq 012D100&lt;br /&gt;
 2020.01.12 14:33:04 2: autocreate: define FileLog_SD_Keeloq_012D100 FileLog ./log/SD_Keeloq_012D100-%Y.log SD_Keeloq_012D100&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 91.1 -&amp;gt; Atlantic security&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 3&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, last part pair=2 reconstructed, last bit=0&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 87 -&amp;gt; JAROLIFT&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 2&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, last part pair=1 reconstructed, last bit=1&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 88 -&amp;gt; HCS300/HCS301&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
und routet die Request an das Modul SD_Keeloq weiter. Der Hinweis auf HCS301 führt auf die richtige Spur. Das analysierte Protokoll KeeLoq ist im Data Sheet des Microchip HCS301 (KeeLoq Code Hopping Encoder) beschrieben. Somit wurde aus einem unbekannten Funkprotokoll letztlich ein bekanntes.&lt;br /&gt;
&lt;br /&gt;
Mittlerweile ist das Protokoll als &#039;&#039;&#039;model enjoy_motors_HS&#039;&#039;&#039; in das Modul &#039;&#039;&#039;SD_Keeloq&#039;&#039;&#039; aufgenommen.&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;br /&gt;
[[Kategorie:868MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32444</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32444"/>
		<updated>2020-01-16T16:38:46Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Finale */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal.png|mini|600px|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|600px|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Fernbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Last but not least meine Konfiguration: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
Register-Settings:&lt;br /&gt;
&lt;br /&gt;
* Trägerfrequenz: 868.302 MHz&lt;br /&gt;
* Deviation: 25 kHz&lt;br /&gt;
* Bandwidth: 58 kHz&lt;br /&gt;
* Baudrate: 24.795 kBaud&lt;br /&gt;
* Modulation: GFSK&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ccregAll: &lt;br /&gt;
&lt;br /&gt;
ccreg 00: 0D 2E 2D 47 D3 91 3D 04 32 00 00 06 00 21 65 6F&lt;br /&gt;
ccreg 10: F9 F4 18 23 B9 40 07 00 18 14 6C 07 00 91 87 6B&lt;br /&gt;
ccreg 20: F8 56 11 EF 2D 12 1F 41 00 59 7F 3F 88 31 0B &lt;br /&gt;
&lt;br /&gt;
Configuration Register Detail (address, name, value):&lt;br /&gt;
0x00 IOCFG2   - 0x0D&lt;br /&gt;
0x01 IOCFG1   - 0x2E&lt;br /&gt;
0x02 IOCFG0   - 0x2D&lt;br /&gt;
0x03 FIFOTHR  - 0x47&lt;br /&gt;
0x04 SYNC1    - 0xD3&lt;br /&gt;
0x05 SYNC0    - 0x91&lt;br /&gt;
0x06 PKTLEN   - 0x3D&lt;br /&gt;
0x07 PKTCTRL1 - 0x04&lt;br /&gt;
0x08 PKTCTRL0 - 0x32&lt;br /&gt;
0x09 ADDR     - 0x00&lt;br /&gt;
0x0A CHANNR   - 0x00&lt;br /&gt;
0x0B FSCTRL1  - 0x06&lt;br /&gt;
0x0C FSCTRL0  - 0x00&lt;br /&gt;
0x0D FREQ2    - 0x21&lt;br /&gt;
0x0E FREQ1    - 0x65&lt;br /&gt;
0x0F FREQ0    - 0x6F&lt;br /&gt;
0x10 MDMCFG4  - 0xF9&lt;br /&gt;
0x11 MDMCFG3  - 0xF4&lt;br /&gt;
0x12 MDMCFG2  - 0x18&lt;br /&gt;
0x13 MDMCFG1  - 0x23&lt;br /&gt;
0x14 MDMCFG0  - 0xB9&lt;br /&gt;
0x15 DEVIATN  - 0x40&lt;br /&gt;
0x16 MCSM2    - 0x07&lt;br /&gt;
0x17 MCSM1    - 0x00&lt;br /&gt;
0x18 MCSM0    - 0x18&lt;br /&gt;
0x19 FOCCFG   - 0x14&lt;br /&gt;
0x1A BSCFG    - 0x6C&lt;br /&gt;
0x1B AGCCTRL2 - 0x07&lt;br /&gt;
0x1C AGCCTRL1 - 0x00&lt;br /&gt;
0x1D AGCCTRL0 - 0x91&lt;br /&gt;
0x1E WOREVT1  - 0x87&lt;br /&gt;
0x1F WOREVT0  - 0x6B&lt;br /&gt;
0x20 WORCTRL  - 0xF8&lt;br /&gt;
0x21 FREND1   - 0x56&lt;br /&gt;
0x22 FREND0   - 0x11&lt;br /&gt;
0x23 FSCAL3   - 0xEF&lt;br /&gt;
0x24 FSCAL2   - 0x2D&lt;br /&gt;
0x25 FSCAL1   - 0x12&lt;br /&gt;
0x26 FSCAL0   - 0x1F&lt;br /&gt;
0x27 RCCTRL1  - 0x41&lt;br /&gt;
0x28 RCCTRL0  - 0x00&lt;br /&gt;
0x29 FSTEST   - 0x59&lt;br /&gt;
0x2A PTEST    - 0x7F&lt;br /&gt;
0x2B AGCTEST  - 0x3F&lt;br /&gt;
0x2C TEST2    - 0x88&lt;br /&gt;
0x2D TEST1    - 0x31&lt;br /&gt;
0x2E TEST0    - 0x0B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Finale ===&lt;br /&gt;
&lt;br /&gt;
Nach Aktivierung der vormals ausgeschalteten Message-Typen im SIGNALduino werden nunmehr SD_Keeloq-Devices angelegt.&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino erkennt &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 2020.01.12 14:33:03 4: mySIGNALduino: Parse_MS, Decoded matched MS Protocol id 88 dmsg P88#74D21B18008B48058 length 68  RSSI = -32&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: Dispatch, P88#74D21B18008B48058, test ungleich: disabled&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: Dispatch, P88#74D21B18008B48058, -32 dB, dispatch&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: dispatch P88#74D21B18008B48058&lt;br /&gt;
 2020.01.12 14:33:04 2: mySIGNALduino: SD_Keeloq_Parse Unknown device unknown with Code 012D100 detected, please define (rawdate=74D21B18008B48058)&lt;br /&gt;
 2020.01.12 14:33:04 2: autocreate: define SD_Keeloq_012D100 SD_Keeloq 012D100&lt;br /&gt;
 2020.01.12 14:33:04 2: autocreate: define FileLog_SD_Keeloq_012D100 FileLog ./log/SD_Keeloq_012D100-%Y.log SD_Keeloq_012D100&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 91.1 -&amp;gt; Atlantic security&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 3&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, last part pair=2 reconstructed, last bit=0&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 87 -&amp;gt; JAROLIFT&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 2&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, last part pair=1 reconstructed, last bit=1&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 88 -&amp;gt; HCS300/HCS301&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
und routet die Request an das Modul SD_Keeloq weiter. Der Hinweis auf HCS301 führt auf die richtige Spur. Das analysierte Protokoll KeeLoq ist im Data Sheet des Microchip HCS301 (KeeLoq Code Hopping Encoder) beschrieben. Somit wurde aus einem unbekannten Funkprotokoll letztlich ein bekanntes.&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;br /&gt;
[[Kategorie:868MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32430</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32430"/>
		<updated>2020-01-12T20:02:47Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Finale */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal.png|mini|600px|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|600px|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Fernbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Last but not least meine Konfiguration: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
Register-Settings:&lt;br /&gt;
&lt;br /&gt;
* Trägerfrequenz: 868.302 MHz&lt;br /&gt;
* Deviation: 25 kHz&lt;br /&gt;
* Bandwidth: 58 kHz&lt;br /&gt;
* Baudrate: 24.795 kBaud&lt;br /&gt;
* Modulation: GFSK&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ccregAll: &lt;br /&gt;
&lt;br /&gt;
ccreg 00: 0D 2E 2D 47 D3 91 3D 04 32 00 00 06 00 21 65 6F&lt;br /&gt;
ccreg 10: F9 F4 18 23 B9 40 07 00 18 14 6C 07 00 91 87 6B&lt;br /&gt;
ccreg 20: F8 56 11 EF 2D 12 1F 41 00 59 7F 3F 88 31 0B &lt;br /&gt;
&lt;br /&gt;
Configuration Register Detail (address, name, value):&lt;br /&gt;
0x00 IOCFG2   - 0x0D&lt;br /&gt;
0x01 IOCFG1   - 0x2E&lt;br /&gt;
0x02 IOCFG0   - 0x2D&lt;br /&gt;
0x03 FIFOTHR  - 0x47&lt;br /&gt;
0x04 SYNC1    - 0xD3&lt;br /&gt;
0x05 SYNC0    - 0x91&lt;br /&gt;
0x06 PKTLEN   - 0x3D&lt;br /&gt;
0x07 PKTCTRL1 - 0x04&lt;br /&gt;
0x08 PKTCTRL0 - 0x32&lt;br /&gt;
0x09 ADDR     - 0x00&lt;br /&gt;
0x0A CHANNR   - 0x00&lt;br /&gt;
0x0B FSCTRL1  - 0x06&lt;br /&gt;
0x0C FSCTRL0  - 0x00&lt;br /&gt;
0x0D FREQ2    - 0x21&lt;br /&gt;
0x0E FREQ1    - 0x65&lt;br /&gt;
0x0F FREQ0    - 0x6F&lt;br /&gt;
0x10 MDMCFG4  - 0xF9&lt;br /&gt;
0x11 MDMCFG3  - 0xF4&lt;br /&gt;
0x12 MDMCFG2  - 0x18&lt;br /&gt;
0x13 MDMCFG1  - 0x23&lt;br /&gt;
0x14 MDMCFG0  - 0xB9&lt;br /&gt;
0x15 DEVIATN  - 0x40&lt;br /&gt;
0x16 MCSM2    - 0x07&lt;br /&gt;
0x17 MCSM1    - 0x00&lt;br /&gt;
0x18 MCSM0    - 0x18&lt;br /&gt;
0x19 FOCCFG   - 0x14&lt;br /&gt;
0x1A BSCFG    - 0x6C&lt;br /&gt;
0x1B AGCCTRL2 - 0x07&lt;br /&gt;
0x1C AGCCTRL1 - 0x00&lt;br /&gt;
0x1D AGCCTRL0 - 0x91&lt;br /&gt;
0x1E WOREVT1  - 0x87&lt;br /&gt;
0x1F WOREVT0  - 0x6B&lt;br /&gt;
0x20 WORCTRL  - 0xF8&lt;br /&gt;
0x21 FREND1   - 0x56&lt;br /&gt;
0x22 FREND0   - 0x11&lt;br /&gt;
0x23 FSCAL3   - 0xEF&lt;br /&gt;
0x24 FSCAL2   - 0x2D&lt;br /&gt;
0x25 FSCAL1   - 0x12&lt;br /&gt;
0x26 FSCAL0   - 0x1F&lt;br /&gt;
0x27 RCCTRL1  - 0x41&lt;br /&gt;
0x28 RCCTRL0  - 0x00&lt;br /&gt;
0x29 FSTEST   - 0x59&lt;br /&gt;
0x2A PTEST    - 0x7F&lt;br /&gt;
0x2B AGCTEST  - 0x3F&lt;br /&gt;
0x2C TEST2    - 0x88&lt;br /&gt;
0x2D TEST1    - 0x31&lt;br /&gt;
0x2E TEST0    - 0x0B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Finale ===&lt;br /&gt;
&lt;br /&gt;
Nach Aktivierung der vormals ausgeschalteten Message-Typen im SIGNALduino werden nunmehr SD_Keeloq-Devices angelegt.&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino erkennt &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 2020.01.12 14:33:03 4: mySIGNALduino: Parse_MS, Decoded matched MS Protocol id 88 dmsg P88#74D21B18008B48058 length 68  RSSI = -32&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: Dispatch, P88#74D21B18008B48058, test ungleich: disabled&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: Dispatch, P88#74D21B18008B48058, -32 dB, dispatch&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: dispatch P88#74D21B18008B48058&lt;br /&gt;
 2020.01.12 14:33:04 2: mySIGNALduino: SD_Keeloq_Parse Unknown device unknown with Code 012D100 detected, please define (rawdate=74D21B18008B48058)&lt;br /&gt;
 2020.01.12 14:33:04 2: autocreate: define SD_Keeloq_012D100 SD_Keeloq 012D100&lt;br /&gt;
 2020.01.12 14:33:04 2: autocreate: define FileLog_SD_Keeloq_012D100 FileLog ./log/SD_Keeloq_012D100-%Y.log SD_Keeloq_012D100&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 91.1 -&amp;gt; Atlantic security&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 3&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, last part pair=2 reconstructed, last bit=0&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 87 -&amp;gt; JAROLIFT&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 2&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, last part pair=1 reconstructed, last bit=1&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 88 -&amp;gt; HCS300/HCS301&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
und routet die Request an das Modul SD_Keeloq weiter. Der Hinweis auf HCS301 führt auf die richtige Spur. Das analysierte Protokoll ist im Data Sheet des Microchip HCS301 (KeeLoq Code Hopping Encoder) beschrieben. Somit wurde aus einem unbekannten Funkprotokoll letztlich ein bekanntes.&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;br /&gt;
[[Kategorie:868MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32428</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32428"/>
		<updated>2020-01-12T17:25:20Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Es geht weiter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal.png|mini|600px|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|600px|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Fernbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Last but not least meine Konfiguration: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
Register-Settings:&lt;br /&gt;
&lt;br /&gt;
* Trägerfrequenz: 868.302 MHz&lt;br /&gt;
* Deviation: 25 kHz&lt;br /&gt;
* Bandwidth: 58 kHz&lt;br /&gt;
* Baudrate: 24.795 kBaud&lt;br /&gt;
* Modulation: GFSK&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ccregAll: &lt;br /&gt;
&lt;br /&gt;
ccreg 00: 0D 2E 2D 47 D3 91 3D 04 32 00 00 06 00 21 65 6F&lt;br /&gt;
ccreg 10: F9 F4 18 23 B9 40 07 00 18 14 6C 07 00 91 87 6B&lt;br /&gt;
ccreg 20: F8 56 11 EF 2D 12 1F 41 00 59 7F 3F 88 31 0B &lt;br /&gt;
&lt;br /&gt;
Configuration Register Detail (address, name, value):&lt;br /&gt;
0x00 IOCFG2   - 0x0D&lt;br /&gt;
0x01 IOCFG1   - 0x2E&lt;br /&gt;
0x02 IOCFG0   - 0x2D&lt;br /&gt;
0x03 FIFOTHR  - 0x47&lt;br /&gt;
0x04 SYNC1    - 0xD3&lt;br /&gt;
0x05 SYNC0    - 0x91&lt;br /&gt;
0x06 PKTLEN   - 0x3D&lt;br /&gt;
0x07 PKTCTRL1 - 0x04&lt;br /&gt;
0x08 PKTCTRL0 - 0x32&lt;br /&gt;
0x09 ADDR     - 0x00&lt;br /&gt;
0x0A CHANNR   - 0x00&lt;br /&gt;
0x0B FSCTRL1  - 0x06&lt;br /&gt;
0x0C FSCTRL0  - 0x00&lt;br /&gt;
0x0D FREQ2    - 0x21&lt;br /&gt;
0x0E FREQ1    - 0x65&lt;br /&gt;
0x0F FREQ0    - 0x6F&lt;br /&gt;
0x10 MDMCFG4  - 0xF9&lt;br /&gt;
0x11 MDMCFG3  - 0xF4&lt;br /&gt;
0x12 MDMCFG2  - 0x18&lt;br /&gt;
0x13 MDMCFG1  - 0x23&lt;br /&gt;
0x14 MDMCFG0  - 0xB9&lt;br /&gt;
0x15 DEVIATN  - 0x40&lt;br /&gt;
0x16 MCSM2    - 0x07&lt;br /&gt;
0x17 MCSM1    - 0x00&lt;br /&gt;
0x18 MCSM0    - 0x18&lt;br /&gt;
0x19 FOCCFG   - 0x14&lt;br /&gt;
0x1A BSCFG    - 0x6C&lt;br /&gt;
0x1B AGCCTRL2 - 0x07&lt;br /&gt;
0x1C AGCCTRL1 - 0x00&lt;br /&gt;
0x1D AGCCTRL0 - 0x91&lt;br /&gt;
0x1E WOREVT1  - 0x87&lt;br /&gt;
0x1F WOREVT0  - 0x6B&lt;br /&gt;
0x20 WORCTRL  - 0xF8&lt;br /&gt;
0x21 FREND1   - 0x56&lt;br /&gt;
0x22 FREND0   - 0x11&lt;br /&gt;
0x23 FSCAL3   - 0xEF&lt;br /&gt;
0x24 FSCAL2   - 0x2D&lt;br /&gt;
0x25 FSCAL1   - 0x12&lt;br /&gt;
0x26 FSCAL0   - 0x1F&lt;br /&gt;
0x27 RCCTRL1  - 0x41&lt;br /&gt;
0x28 RCCTRL0  - 0x00&lt;br /&gt;
0x29 FSTEST   - 0x59&lt;br /&gt;
0x2A PTEST    - 0x7F&lt;br /&gt;
0x2B AGCTEST  - 0x3F&lt;br /&gt;
0x2C TEST2    - 0x88&lt;br /&gt;
0x2D TEST1    - 0x31&lt;br /&gt;
0x2E TEST0    - 0x0B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Finale ===&lt;br /&gt;
&lt;br /&gt;
Nach Aktivierung der vormals ausgeschalteten Message-Typen im SIGNALduino werden nunmehr SD_Keeloq-Devices angelegt.&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino erkennt &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 2020.01.12 14:33:03 4: mySIGNALduino: Parse_MS, Decoded matched MS Protocol id 88 dmsg P88#74D21B18008B48058 length 68  RSSI = -32&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: Dispatch, P88#74D21B18008B48058, test ungleich: disabled&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: Dispatch, P88#74D21B18008B48058, -32 dB, dispatch&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: dispatch P88#74D21B18008B48058&lt;br /&gt;
 2020.01.12 14:33:04 2: mySIGNALduino: SD_Keeloq_Parse Unknown device unknown with Code 012D100 detected, please define (rawdate=74D21B18008B48058)&lt;br /&gt;
 2020.01.12 14:33:04 2: autocreate: define SD_Keeloq_012D100 SD_Keeloq 012D100&lt;br /&gt;
 2020.01.12 14:33:04 2: autocreate: define FileLog_SD_Keeloq_012D100 FileLog ./log/SD_Keeloq_012D100-%Y.log SD_Keeloq_012D100&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 91.1 -&amp;gt; Atlantic security&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 3&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, last part pair=2 reconstructed, last bit=0&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 87 -&amp;gt; JAROLIFT&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 2&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, last part pair=1 reconstructed, last bit=1&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 88 -&amp;gt; HCS300/HCS301&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
und routet die Request an das Modul SD_Keeloq weiter. Der Hinweis auf HCS301 führt auf die richtige Spur. Das analysierte Protkoll ist im Data Sheet des Microchip HCS301 (KeeLoq Code Hopping Encoder) beschrieben. Somit wurde aus einem unbekannten Funkprotokoll letztlich ein bekanntes.&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;br /&gt;
[[Kategorie:868MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32427</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32427"/>
		<updated>2020-01-12T17:25:04Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Es geht weiter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal.png|mini|600px|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|600px|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Fernbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Last but not least meine Konfiguration: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
Register-Settings:&lt;br /&gt;
&lt;br /&gt;
* Trägerfrequenz: 868.302 MHz&lt;br /&gt;
* Deviation: 25 kHz&lt;br /&gt;
* Bandwidth: 58 kHz&lt;br /&gt;
* Baudrate: 24.795 kBaud&lt;br /&gt;
* Modulation: GFSK&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ccregAll: &lt;br /&gt;
&lt;br /&gt;
ccreg 00: 0D 2E 2D 47 D3 91 3D 04 32 00 00 06 00 21 65 6F&lt;br /&gt;
ccreg 10: F9 F4 18 23 B9 40 07 00 18 14 6C 07 00 91 87 6B&lt;br /&gt;
ccreg 20: F8 56 11 EF 2D 12 1F 41 00 59 7F 3F 88 31 0B &lt;br /&gt;
&lt;br /&gt;
Configuration Register Detail (address, name, value):&lt;br /&gt;
0x00 IOCFG2   - 0x0D&lt;br /&gt;
0x01 IOCFG1   - 0x2E&lt;br /&gt;
0x02 IOCFG0   - 0x2D&lt;br /&gt;
0x03 FIFOTHR  - 0x47&lt;br /&gt;
0x04 SYNC1    - 0xD3&lt;br /&gt;
0x05 SYNC0    - 0x91&lt;br /&gt;
0x06 PKTLEN   - 0x3D&lt;br /&gt;
0x07 PKTCTRL1 - 0x04&lt;br /&gt;
0x08 PKTCTRL0 - 0x32&lt;br /&gt;
0x09 ADDR     - 0x00&lt;br /&gt;
0x0A CHANNR   - 0x00&lt;br /&gt;
0x0B FSCTRL1  - 0x06&lt;br /&gt;
0x0C FSCTRL0  - 0x00&lt;br /&gt;
0x0D FREQ2    - 0x21&lt;br /&gt;
0x0E FREQ1    - 0x65&lt;br /&gt;
0x0F FREQ0    - 0x6F&lt;br /&gt;
0x10 MDMCFG4  - 0xF9&lt;br /&gt;
0x11 MDMCFG3  - 0xF4&lt;br /&gt;
0x12 MDMCFG2  - 0x18&lt;br /&gt;
0x13 MDMCFG1  - 0x23&lt;br /&gt;
0x14 MDMCFG0  - 0xB9&lt;br /&gt;
0x15 DEVIATN  - 0x40&lt;br /&gt;
0x16 MCSM2    - 0x07&lt;br /&gt;
0x17 MCSM1    - 0x00&lt;br /&gt;
0x18 MCSM0    - 0x18&lt;br /&gt;
0x19 FOCCFG   - 0x14&lt;br /&gt;
0x1A BSCFG    - 0x6C&lt;br /&gt;
0x1B AGCCTRL2 - 0x07&lt;br /&gt;
0x1C AGCCTRL1 - 0x00&lt;br /&gt;
0x1D AGCCTRL0 - 0x91&lt;br /&gt;
0x1E WOREVT1  - 0x87&lt;br /&gt;
0x1F WOREVT0  - 0x6B&lt;br /&gt;
0x20 WORCTRL  - 0xF8&lt;br /&gt;
0x21 FREND1   - 0x56&lt;br /&gt;
0x22 FREND0   - 0x11&lt;br /&gt;
0x23 FSCAL3   - 0xEF&lt;br /&gt;
0x24 FSCAL2   - 0x2D&lt;br /&gt;
0x25 FSCAL1   - 0x12&lt;br /&gt;
0x26 FSCAL0   - 0x1F&lt;br /&gt;
0x27 RCCTRL1  - 0x41&lt;br /&gt;
0x28 RCCTRL0  - 0x00&lt;br /&gt;
0x29 FSTEST   - 0x59&lt;br /&gt;
0x2A PTEST    - 0x7F&lt;br /&gt;
0x2B AGCTEST  - 0x3F&lt;br /&gt;
0x2C TEST2    - 0x88&lt;br /&gt;
0x2D TEST1    - 0x31&lt;br /&gt;
0x2E TEST0    - 0x0B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Es geht weiter ===&lt;br /&gt;
&lt;br /&gt;
Nach Aktivierung der vormals ausgeschalteten Message-Typen im SIGNALduino werden nunmehr SD_Keeloq-Devices angelegt.&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino erkennt &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 2020.01.12 14:33:03 4: mySIGNALduino: Parse_MS, Decoded matched MS Protocol id 88 dmsg P88#74D21B18008B48058 length 68  RSSI = -32&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: Dispatch, P88#74D21B18008B48058, test ungleich: disabled&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: Dispatch, P88#74D21B18008B48058, -32 dB, dispatch&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: dispatch P88#74D21B18008B48058&lt;br /&gt;
 2020.01.12 14:33:04 2: mySIGNALduino: SD_Keeloq_Parse Unknown device unknown with Code 012D100 detected, please define (rawdate=74D21B18008B48058)&lt;br /&gt;
 2020.01.12 14:33:04 2: autocreate: define SD_Keeloq_012D100 SD_Keeloq 012D100&lt;br /&gt;
 2020.01.12 14:33:04 2: autocreate: define FileLog_SD_Keeloq_012D100 FileLog ./log/SD_Keeloq_012D100-%Y.log SD_Keeloq_012D100&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 91.1 -&amp;gt; Atlantic security&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 3&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, last part pair=2 reconstructed, last bit=0&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 87 -&amp;gt; JAROLIFT&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 2&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, last part pair=1 reconstructed, last bit=1&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 88 -&amp;gt; HCS300/HCS301&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
und routet die Request an das Modul SD_Keeloq weiter. Der Hinweis auf HCS301 führt auf die richtige Spur. Das analysierte Protkoll ist im Data Sheet des Microchip HCS301 (KeeLoq Code Hopping Encoder) beschrieben. Somit wurde aus einem unbekannten Funkprotokoll letztlich ein bekanntes.&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;br /&gt;
[[Kategorie:868MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32426</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32426"/>
		<updated>2020-01-12T16:54:37Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Es geht weiter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal.png|mini|600px|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|600px|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Fernbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Last but not least meine Konfiguration: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
Register-Settings:&lt;br /&gt;
&lt;br /&gt;
* Trägerfrequenz: 868.302 MHz&lt;br /&gt;
* Deviation: 25 kHz&lt;br /&gt;
* Bandwidth: 58 kHz&lt;br /&gt;
* Baudrate: 24.795 kBaud&lt;br /&gt;
* Modulation: GFSK&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ccregAll: &lt;br /&gt;
&lt;br /&gt;
ccreg 00: 0D 2E 2D 47 D3 91 3D 04 32 00 00 06 00 21 65 6F&lt;br /&gt;
ccreg 10: F9 F4 18 23 B9 40 07 00 18 14 6C 07 00 91 87 6B&lt;br /&gt;
ccreg 20: F8 56 11 EF 2D 12 1F 41 00 59 7F 3F 88 31 0B &lt;br /&gt;
&lt;br /&gt;
Configuration Register Detail (address, name, value):&lt;br /&gt;
0x00 IOCFG2   - 0x0D&lt;br /&gt;
0x01 IOCFG1   - 0x2E&lt;br /&gt;
0x02 IOCFG0   - 0x2D&lt;br /&gt;
0x03 FIFOTHR  - 0x47&lt;br /&gt;
0x04 SYNC1    - 0xD3&lt;br /&gt;
0x05 SYNC0    - 0x91&lt;br /&gt;
0x06 PKTLEN   - 0x3D&lt;br /&gt;
0x07 PKTCTRL1 - 0x04&lt;br /&gt;
0x08 PKTCTRL0 - 0x32&lt;br /&gt;
0x09 ADDR     - 0x00&lt;br /&gt;
0x0A CHANNR   - 0x00&lt;br /&gt;
0x0B FSCTRL1  - 0x06&lt;br /&gt;
0x0C FSCTRL0  - 0x00&lt;br /&gt;
0x0D FREQ2    - 0x21&lt;br /&gt;
0x0E FREQ1    - 0x65&lt;br /&gt;
0x0F FREQ0    - 0x6F&lt;br /&gt;
0x10 MDMCFG4  - 0xF9&lt;br /&gt;
0x11 MDMCFG3  - 0xF4&lt;br /&gt;
0x12 MDMCFG2  - 0x18&lt;br /&gt;
0x13 MDMCFG1  - 0x23&lt;br /&gt;
0x14 MDMCFG0  - 0xB9&lt;br /&gt;
0x15 DEVIATN  - 0x40&lt;br /&gt;
0x16 MCSM2    - 0x07&lt;br /&gt;
0x17 MCSM1    - 0x00&lt;br /&gt;
0x18 MCSM0    - 0x18&lt;br /&gt;
0x19 FOCCFG   - 0x14&lt;br /&gt;
0x1A BSCFG    - 0x6C&lt;br /&gt;
0x1B AGCCTRL2 - 0x07&lt;br /&gt;
0x1C AGCCTRL1 - 0x00&lt;br /&gt;
0x1D AGCCTRL0 - 0x91&lt;br /&gt;
0x1E WOREVT1  - 0x87&lt;br /&gt;
0x1F WOREVT0  - 0x6B&lt;br /&gt;
0x20 WORCTRL  - 0xF8&lt;br /&gt;
0x21 FREND1   - 0x56&lt;br /&gt;
0x22 FREND0   - 0x11&lt;br /&gt;
0x23 FSCAL3   - 0xEF&lt;br /&gt;
0x24 FSCAL2   - 0x2D&lt;br /&gt;
0x25 FSCAL1   - 0x12&lt;br /&gt;
0x26 FSCAL0   - 0x1F&lt;br /&gt;
0x27 RCCTRL1  - 0x41&lt;br /&gt;
0x28 RCCTRL0  - 0x00&lt;br /&gt;
0x29 FSTEST   - 0x59&lt;br /&gt;
0x2A PTEST    - 0x7F&lt;br /&gt;
0x2B AGCTEST  - 0x3F&lt;br /&gt;
0x2C TEST2    - 0x88&lt;br /&gt;
0x2D TEST1    - 0x31&lt;br /&gt;
0x2E TEST0    - 0x0B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Es geht weiter ===&lt;br /&gt;
&lt;br /&gt;
Nach Aktivierung der vormals ausgeschalteten Message-Typen im SIGNALduino werden nunmehr SD_Keeloq-Devices angelegt.&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino erkennt &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 2020.01.12 14:33:03 4: mySIGNALduino: Parse_MS, Decoded matched MS Protocol id 88 dmsg P88#74D21B18008B48058 length 68  RSSI = -32&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: Dispatch, P88#74D21B18008B48058, test ungleich: disabled&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: Dispatch, P88#74D21B18008B48058, -32 dB, dispatch&lt;br /&gt;
 2020.01.12 14:33:03 5: mySIGNALduino: dispatch P88#74D21B18008B48058&lt;br /&gt;
 2020.01.12 14:33:04 2: mySIGNALduino: SD_Keeloq_Parse Unknown device unknown with Code 012D100 detected, please define (rawdate=74D21B18008B48058)&lt;br /&gt;
 2020.01.12 14:33:04 2: autocreate: define SD_Keeloq_012D100 SD_Keeloq 012D100&lt;br /&gt;
 2020.01.12 14:33:04 2: autocreate: define FileLog_SD_Keeloq_012D100 FileLog ./log/SD_Keeloq_012D100-%Y.log SD_Keeloq_012D100&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 91.1 -&amp;gt; Atlantic security&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 3&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, last part pair=2 reconstructed, last bit=0&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 87 -&amp;gt; JAROLIFT&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 2&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, last part pair=1 reconstructed, last bit=1&lt;br /&gt;
 2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 88 -&amp;gt; HCS300/HCS301&lt;br /&gt;
 2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 2&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
und routet die Request an das Modul SD_Keeloq weiter. Der Hinweis auf HCS301 führt auf die richtige Spur. Das analysierte Protkoll ist im Data Sheet des Microchip HCS301 (KeeLoq Code Hopping Encoder) beschrieben. Somit wurde aus einem unbekannten Funkprotokoll letztlich ein bekanntes.&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;br /&gt;
[[Kategorie:868MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32425</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32425"/>
		<updated>2020-01-12T16:52:57Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Es geht weiter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal.png|mini|600px|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|600px|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Fernbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Last but not least meine Konfiguration: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
Register-Settings:&lt;br /&gt;
&lt;br /&gt;
* Trägerfrequenz: 868.302 MHz&lt;br /&gt;
* Deviation: 25 kHz&lt;br /&gt;
* Bandwidth: 58 kHz&lt;br /&gt;
* Baudrate: 24.795 kBaud&lt;br /&gt;
* Modulation: GFSK&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ccregAll: &lt;br /&gt;
&lt;br /&gt;
ccreg 00: 0D 2E 2D 47 D3 91 3D 04 32 00 00 06 00 21 65 6F&lt;br /&gt;
ccreg 10: F9 F4 18 23 B9 40 07 00 18 14 6C 07 00 91 87 6B&lt;br /&gt;
ccreg 20: F8 56 11 EF 2D 12 1F 41 00 59 7F 3F 88 31 0B &lt;br /&gt;
&lt;br /&gt;
Configuration Register Detail (address, name, value):&lt;br /&gt;
0x00 IOCFG2   - 0x0D&lt;br /&gt;
0x01 IOCFG1   - 0x2E&lt;br /&gt;
0x02 IOCFG0   - 0x2D&lt;br /&gt;
0x03 FIFOTHR  - 0x47&lt;br /&gt;
0x04 SYNC1    - 0xD3&lt;br /&gt;
0x05 SYNC0    - 0x91&lt;br /&gt;
0x06 PKTLEN   - 0x3D&lt;br /&gt;
0x07 PKTCTRL1 - 0x04&lt;br /&gt;
0x08 PKTCTRL0 - 0x32&lt;br /&gt;
0x09 ADDR     - 0x00&lt;br /&gt;
0x0A CHANNR   - 0x00&lt;br /&gt;
0x0B FSCTRL1  - 0x06&lt;br /&gt;
0x0C FSCTRL0  - 0x00&lt;br /&gt;
0x0D FREQ2    - 0x21&lt;br /&gt;
0x0E FREQ1    - 0x65&lt;br /&gt;
0x0F FREQ0    - 0x6F&lt;br /&gt;
0x10 MDMCFG4  - 0xF9&lt;br /&gt;
0x11 MDMCFG3  - 0xF4&lt;br /&gt;
0x12 MDMCFG2  - 0x18&lt;br /&gt;
0x13 MDMCFG1  - 0x23&lt;br /&gt;
0x14 MDMCFG0  - 0xB9&lt;br /&gt;
0x15 DEVIATN  - 0x40&lt;br /&gt;
0x16 MCSM2    - 0x07&lt;br /&gt;
0x17 MCSM1    - 0x00&lt;br /&gt;
0x18 MCSM0    - 0x18&lt;br /&gt;
0x19 FOCCFG   - 0x14&lt;br /&gt;
0x1A BSCFG    - 0x6C&lt;br /&gt;
0x1B AGCCTRL2 - 0x07&lt;br /&gt;
0x1C AGCCTRL1 - 0x00&lt;br /&gt;
0x1D AGCCTRL0 - 0x91&lt;br /&gt;
0x1E WOREVT1  - 0x87&lt;br /&gt;
0x1F WOREVT0  - 0x6B&lt;br /&gt;
0x20 WORCTRL  - 0xF8&lt;br /&gt;
0x21 FREND1   - 0x56&lt;br /&gt;
0x22 FREND0   - 0x11&lt;br /&gt;
0x23 FSCAL3   - 0xEF&lt;br /&gt;
0x24 FSCAL2   - 0x2D&lt;br /&gt;
0x25 FSCAL1   - 0x12&lt;br /&gt;
0x26 FSCAL0   - 0x1F&lt;br /&gt;
0x27 RCCTRL1  - 0x41&lt;br /&gt;
0x28 RCCTRL0  - 0x00&lt;br /&gt;
0x29 FSTEST   - 0x59&lt;br /&gt;
0x2A PTEST    - 0x7F&lt;br /&gt;
0x2B AGCTEST  - 0x3F&lt;br /&gt;
0x2C TEST2    - 0x88&lt;br /&gt;
0x2D TEST1    - 0x31&lt;br /&gt;
0x2E TEST0    - 0x0B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Es geht weiter ===&lt;br /&gt;
&lt;br /&gt;
Nach Aktivierung der vormals ausgeschalteten Message-Typen im SIGNALduino werden nunmehr SD_Keeloq-Devices angelegt.&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino erkennt &lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
2020.01.12 14:33:03 4: mySIGNALduino: Parse_MS, Decoded matched MS Protocol id 88 dmsg P88#74D21B18008B48058 length 68  RSSI = -32&lt;br /&gt;
2020.01.12 14:33:03 5: mySIGNALduino: Dispatch, P88#74D21B18008B48058, test ungleich: disabled&lt;br /&gt;
2020.01.12 14:33:03 5: mySIGNALduino: Dispatch, P88#74D21B18008B48058, -32 dB, dispatch&lt;br /&gt;
2020.01.12 14:33:03 5: mySIGNALduino: dispatch P88#74D21B18008B48058&lt;br /&gt;
2020.01.12 14:33:04 2: mySIGNALduino: SD_Keeloq_Parse Unknown device unknown with Code 012D100 detected, please define (rawdate=74D21B18008B48058)&lt;br /&gt;
2020.01.12 14:33:04 2: autocreate: define SD_Keeloq_012D100 SD_Keeloq 012D100&lt;br /&gt;
2020.01.12 14:33:04 2: autocreate: define FileLog_SD_Keeloq_012D100 FileLog ./log/SD_Keeloq_012D100-%Y.log SD_Keeloq_012D100&lt;br /&gt;
2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 91.1 -&amp;gt; Atlantic security&lt;br /&gt;
2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 3&lt;br /&gt;
2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, last part pair=2 reconstructed, last bit=0&lt;br /&gt;
2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 87 -&amp;gt; JAROLIFT&lt;br /&gt;
2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 2&lt;br /&gt;
2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, last part pair=1 reconstructed, last bit=1&lt;br /&gt;
2020.01.12 14:33:04 4: mySIGNALduino: Parse_MS, Matched MS Protocol id 88 -&amp;gt; HCS300/HCS301&lt;br /&gt;
2020.01.12 14:33:04 5: mySIGNALduino: Parse_MS, Starting demodulation at Position 2&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
und routet die Request an das Modul SD_Keeloq weiter. Der Hinweis auf HCS301 führt auf die richtige Spur. Das analysierte Protkoll ist im Data Sheet des Microchio HCS301 (KeeLoq Code Hopping Encoder) beschrieben. Somit wurde aus einem unbekannten Funkprotokoll letztlich ein bekanntes.&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;br /&gt;
[[Kategorie:868MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32411</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32411"/>
		<updated>2020-01-11T17:41:12Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Konfiguration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal.png|mini|600px|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|600px|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Fernbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Last but not least meine Konfiguration: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
Register-Settings:&lt;br /&gt;
&lt;br /&gt;
* Trägerfrequenz: 868.302 MHz&lt;br /&gt;
* Deviation: 25 kHz&lt;br /&gt;
* Bandwidth: 58 kHz&lt;br /&gt;
* Baudrate: 24.795 kBaud&lt;br /&gt;
* Modulation: GFSK&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ccregAll: &lt;br /&gt;
&lt;br /&gt;
ccreg 00: 0D 2E 2D 47 D3 91 3D 04 32 00 00 06 00 21 65 6F&lt;br /&gt;
ccreg 10: F9 F4 18 23 B9 40 07 00 18 14 6C 07 00 91 87 6B&lt;br /&gt;
ccreg 20: F8 56 11 EF 2D 12 1F 41 00 59 7F 3F 88 31 0B &lt;br /&gt;
&lt;br /&gt;
Configuration Register Detail (address, name, value):&lt;br /&gt;
0x00 IOCFG2   - 0x0D&lt;br /&gt;
0x01 IOCFG1   - 0x2E&lt;br /&gt;
0x02 IOCFG0   - 0x2D&lt;br /&gt;
0x03 FIFOTHR  - 0x47&lt;br /&gt;
0x04 SYNC1    - 0xD3&lt;br /&gt;
0x05 SYNC0    - 0x91&lt;br /&gt;
0x06 PKTLEN   - 0x3D&lt;br /&gt;
0x07 PKTCTRL1 - 0x04&lt;br /&gt;
0x08 PKTCTRL0 - 0x32&lt;br /&gt;
0x09 ADDR     - 0x00&lt;br /&gt;
0x0A CHANNR   - 0x00&lt;br /&gt;
0x0B FSCTRL1  - 0x06&lt;br /&gt;
0x0C FSCTRL0  - 0x00&lt;br /&gt;
0x0D FREQ2    - 0x21&lt;br /&gt;
0x0E FREQ1    - 0x65&lt;br /&gt;
0x0F FREQ0    - 0x6F&lt;br /&gt;
0x10 MDMCFG4  - 0xF9&lt;br /&gt;
0x11 MDMCFG3  - 0xF4&lt;br /&gt;
0x12 MDMCFG2  - 0x18&lt;br /&gt;
0x13 MDMCFG1  - 0x23&lt;br /&gt;
0x14 MDMCFG0  - 0xB9&lt;br /&gt;
0x15 DEVIATN  - 0x40&lt;br /&gt;
0x16 MCSM2    - 0x07&lt;br /&gt;
0x17 MCSM1    - 0x00&lt;br /&gt;
0x18 MCSM0    - 0x18&lt;br /&gt;
0x19 FOCCFG   - 0x14&lt;br /&gt;
0x1A BSCFG    - 0x6C&lt;br /&gt;
0x1B AGCCTRL2 - 0x07&lt;br /&gt;
0x1C AGCCTRL1 - 0x00&lt;br /&gt;
0x1D AGCCTRL0 - 0x91&lt;br /&gt;
0x1E WOREVT1  - 0x87&lt;br /&gt;
0x1F WOREVT0  - 0x6B&lt;br /&gt;
0x20 WORCTRL  - 0xF8&lt;br /&gt;
0x21 FREND1   - 0x56&lt;br /&gt;
0x22 FREND0   - 0x11&lt;br /&gt;
0x23 FSCAL3   - 0xEF&lt;br /&gt;
0x24 FSCAL2   - 0x2D&lt;br /&gt;
0x25 FSCAL1   - 0x12&lt;br /&gt;
0x26 FSCAL0   - 0x1F&lt;br /&gt;
0x27 RCCTRL1  - 0x41&lt;br /&gt;
0x28 RCCTRL0  - 0x00&lt;br /&gt;
0x29 FSTEST   - 0x59&lt;br /&gt;
0x2A PTEST    - 0x7F&lt;br /&gt;
0x2B AGCTEST  - 0x3F&lt;br /&gt;
0x2C TEST2    - 0x88&lt;br /&gt;
0x2D TEST1    - 0x31&lt;br /&gt;
0x2E TEST0    - 0x0B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Es geht weiter ===&lt;br /&gt;
&lt;br /&gt;
Nach Aktivierung der vormals ausgeschalteten MessaegTypen im SIGNALduino werden nunmehr SD_Keeloq-Devices angelegt.&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;br /&gt;
[[Kategorie:868MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32247</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32247"/>
		<updated>2019-12-31T08:06:21Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Konfiguration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal.png|mini|600px|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|600px|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Fernbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Last but not least meine Konfiguration: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
Register-Settings:&lt;br /&gt;
&lt;br /&gt;
* Trägerfrequenz: 868.302 MHz&lt;br /&gt;
* Deviation: 25 kHz&lt;br /&gt;
* Bandwidth: 58 kHz&lt;br /&gt;
* Baudrate: 24.795 kBaud&lt;br /&gt;
* Modulation: GFSK&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ccregAll: &lt;br /&gt;
&lt;br /&gt;
ccreg 00: 0D 2E 2D 47 D3 91 3D 04 32 00 00 06 00 21 65 6F&lt;br /&gt;
ccreg 10: F9 F4 18 23 B9 40 07 00 18 14 6C 07 00 91 87 6B&lt;br /&gt;
ccreg 20: F8 56 11 EF 2D 12 1F 41 00 59 7F 3F 88 31 0B &lt;br /&gt;
&lt;br /&gt;
Configuration Register Detail (address, name, value):&lt;br /&gt;
0x00 IOCFG2   - 0x0D&lt;br /&gt;
0x01 IOCFG1   - 0x2E&lt;br /&gt;
0x02 IOCFG0   - 0x2D&lt;br /&gt;
0x03 FIFOTHR  - 0x47&lt;br /&gt;
0x04 SYNC1    - 0xD3&lt;br /&gt;
0x05 SYNC0    - 0x91&lt;br /&gt;
0x06 PKTLEN   - 0x3D&lt;br /&gt;
0x07 PKTCTRL1 - 0x04&lt;br /&gt;
0x08 PKTCTRL0 - 0x32&lt;br /&gt;
0x09 ADDR     - 0x00&lt;br /&gt;
0x0A CHANNR   - 0x00&lt;br /&gt;
0x0B FSCTRL1  - 0x06&lt;br /&gt;
0x0C FSCTRL0  - 0x00&lt;br /&gt;
0x0D FREQ2    - 0x21&lt;br /&gt;
0x0E FREQ1    - 0x65&lt;br /&gt;
0x0F FREQ0    - 0x6F&lt;br /&gt;
0x10 MDMCFG4  - 0xF9&lt;br /&gt;
0x11 MDMCFG3  - 0xF4&lt;br /&gt;
0x12 MDMCFG2  - 0x18&lt;br /&gt;
0x13 MDMCFG1  - 0x23&lt;br /&gt;
0x14 MDMCFG0  - 0xB9&lt;br /&gt;
0x15 DEVIATN  - 0x40&lt;br /&gt;
0x16 MCSM2    - 0x07&lt;br /&gt;
0x17 MCSM1    - 0x00&lt;br /&gt;
0x18 MCSM0    - 0x18&lt;br /&gt;
0x19 FOCCFG   - 0x14&lt;br /&gt;
0x1A BSCFG    - 0x6C&lt;br /&gt;
0x1B AGCCTRL2 - 0x07&lt;br /&gt;
0x1C AGCCTRL1 - 0x00&lt;br /&gt;
0x1D AGCCTRL0 - 0x91&lt;br /&gt;
0x1E WOREVT1  - 0x87&lt;br /&gt;
0x1F WOREVT0  - 0x6B&lt;br /&gt;
0x20 WORCTRL  - 0xF8&lt;br /&gt;
0x21 FREND1   - 0x56&lt;br /&gt;
0x22 FREND0   - 0x11&lt;br /&gt;
0x23 FSCAL3   - 0xEF&lt;br /&gt;
0x24 FSCAL2   - 0x2D&lt;br /&gt;
0x25 FSCAL1   - 0x12&lt;br /&gt;
0x26 FSCAL0   - 0x1F&lt;br /&gt;
0x27 RCCTRL1  - 0x41&lt;br /&gt;
0x28 RCCTRL0  - 0x00&lt;br /&gt;
0x29 FSTEST   - 0x59&lt;br /&gt;
0x2A PTEST    - 0x7F&lt;br /&gt;
0x2B AGCTEST  - 0x3F&lt;br /&gt;
0x2C TEST2    - 0x88&lt;br /&gt;
0x2D TEST1    - 0x31&lt;br /&gt;
0x2E TEST0    - 0x0B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;br /&gt;
[[Kategorie:868MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32246</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32246"/>
		<updated>2019-12-31T08:04:27Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* SIGNALduino - FSK */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal.png|mini|600px|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|600px|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Fernbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Last but not least: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
Register-Settings:&lt;br /&gt;
&lt;br /&gt;
* Trägerfrequenz: 868.302 MHz&lt;br /&gt;
* Deviation: 25 kHz&lt;br /&gt;
* Bandwidth: 58 kHz&lt;br /&gt;
* Baudrate: 24.795 kBaud&lt;br /&gt;
* Modulation: GFSK&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ccregAll: &lt;br /&gt;
&lt;br /&gt;
ccreg 00: 0D 2E 2D 47 D3 91 3D 04 32 00 00 06 00 21 65 6F&lt;br /&gt;
ccreg 10: F9 F4 18 23 B9 40 07 00 18 14 6C 07 00 91 87 6B&lt;br /&gt;
ccreg 20: F8 56 11 EF 2D 12 1F 41 00 59 7F 3F 88 31 0B &lt;br /&gt;
&lt;br /&gt;
Configuration Register Detail (address, name, value):&lt;br /&gt;
0x00 IOCFG2   - 0x0D&lt;br /&gt;
0x01 IOCFG1   - 0x2E&lt;br /&gt;
0x02 IOCFG0   - 0x2D&lt;br /&gt;
0x03 FIFOTHR  - 0x47&lt;br /&gt;
0x04 SYNC1    - 0xD3&lt;br /&gt;
0x05 SYNC0    - 0x91&lt;br /&gt;
0x06 PKTLEN   - 0x3D&lt;br /&gt;
0x07 PKTCTRL1 - 0x04&lt;br /&gt;
0x08 PKTCTRL0 - 0x32&lt;br /&gt;
0x09 ADDR     - 0x00&lt;br /&gt;
0x0A CHANNR   - 0x00&lt;br /&gt;
0x0B FSCTRL1  - 0x06&lt;br /&gt;
0x0C FSCTRL0  - 0x00&lt;br /&gt;
0x0D FREQ2    - 0x21&lt;br /&gt;
0x0E FREQ1    - 0x65&lt;br /&gt;
0x0F FREQ0    - 0x6F&lt;br /&gt;
0x10 MDMCFG4  - 0xF9&lt;br /&gt;
0x11 MDMCFG3  - 0xF4&lt;br /&gt;
0x12 MDMCFG2  - 0x18&lt;br /&gt;
0x13 MDMCFG1  - 0x23&lt;br /&gt;
0x14 MDMCFG0  - 0xB9&lt;br /&gt;
0x15 DEVIATN  - 0x40&lt;br /&gt;
0x16 MCSM2    - 0x07&lt;br /&gt;
0x17 MCSM1    - 0x00&lt;br /&gt;
0x18 MCSM0    - 0x18&lt;br /&gt;
0x19 FOCCFG   - 0x14&lt;br /&gt;
0x1A BSCFG    - 0x6C&lt;br /&gt;
0x1B AGCCTRL2 - 0x07&lt;br /&gt;
0x1C AGCCTRL1 - 0x00&lt;br /&gt;
0x1D AGCCTRL0 - 0x91&lt;br /&gt;
0x1E WOREVT1  - 0x87&lt;br /&gt;
0x1F WOREVT0  - 0x6B&lt;br /&gt;
0x20 WORCTRL  - 0xF8&lt;br /&gt;
0x21 FREND1   - 0x56&lt;br /&gt;
0x22 FREND0   - 0x11&lt;br /&gt;
0x23 FSCAL3   - 0xEF&lt;br /&gt;
0x24 FSCAL2   - 0x2D&lt;br /&gt;
0x25 FSCAL1   - 0x12&lt;br /&gt;
0x26 FSCAL0   - 0x1F&lt;br /&gt;
0x27 RCCTRL1  - 0x41&lt;br /&gt;
0x28 RCCTRL0  - 0x00&lt;br /&gt;
0x29 FSTEST   - 0x59&lt;br /&gt;
0x2A PTEST    - 0x7F&lt;br /&gt;
0x2B AGCTEST  - 0x3F&lt;br /&gt;
0x2C TEST2    - 0x88&lt;br /&gt;
0x2D TEST1    - 0x31&lt;br /&gt;
0x2E TEST0    - 0x0B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;br /&gt;
[[Kategorie:868MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32245</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32245"/>
		<updated>2019-12-30T20:57:36Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Baudrate */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal.png|mini|600px|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|600px|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Fernbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Last but not least: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
Register-Settings:&lt;br /&gt;
&lt;br /&gt;
* Trägerfrequenz: 868.302 MHz&lt;br /&gt;
* Deviation: 25 kHz&lt;br /&gt;
* Bandwidth: 58 kHz&lt;br /&gt;
* Baudrate: 24.795 kBaud&lt;br /&gt;
* Modulation: GFSK&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ccregAll: &lt;br /&gt;
&lt;br /&gt;
ccreg 00: 0D 2E 2D 47 D3 91 3D 04 32 00 00 06 00 21 65 6F&lt;br /&gt;
ccreg 10: F9 F4 18 23 B9 40 07 00 18 14 6C 07 00 91 87 6B&lt;br /&gt;
ccreg 20: F8 56 11 EF 2D 12 1F 41 00 59 7F 3F 88 31 0B &lt;br /&gt;
&lt;br /&gt;
Configuration Register Detail (address, name, value):&lt;br /&gt;
0x00 IOCFG2   - 0x0D&lt;br /&gt;
0x01 IOCFG1   - 0x2E&lt;br /&gt;
0x02 IOCFG0   - 0x2D&lt;br /&gt;
0x03 FIFOTHR  - 0x47&lt;br /&gt;
0x04 SYNC1    - 0xD3&lt;br /&gt;
0x05 SYNC0    - 0x91&lt;br /&gt;
0x06 PKTLEN   - 0x3D&lt;br /&gt;
0x07 PKTCTRL1 - 0x04&lt;br /&gt;
0x08 PKTCTRL0 - 0x32&lt;br /&gt;
0x09 ADDR     - 0x00&lt;br /&gt;
0x0A CHANNR   - 0x00&lt;br /&gt;
0x0B FSCTRL1  - 0x06&lt;br /&gt;
0x0C FSCTRL0  - 0x00&lt;br /&gt;
0x0D FREQ2    - 0x21&lt;br /&gt;
0x0E FREQ1    - 0x65&lt;br /&gt;
0x0F FREQ0    - 0x6F&lt;br /&gt;
0x10 MDMCFG4  - 0xF9&lt;br /&gt;
0x11 MDMCFG3  - 0xF4&lt;br /&gt;
0x12 MDMCFG2  - 0x18&lt;br /&gt;
0x13 MDMCFG1  - 0x23&lt;br /&gt;
0x14 MDMCFG0  - 0xB9&lt;br /&gt;
0x15 DEVIATN  - 0x40&lt;br /&gt;
0x16 MCSM2    - 0x07&lt;br /&gt;
0x17 MCSM1    - 0x00&lt;br /&gt;
0x18 MCSM0    - 0x18&lt;br /&gt;
0x19 FOCCFG   - 0x14&lt;br /&gt;
0x1A BSCFG    - 0x6C&lt;br /&gt;
0x1B AGCCTRL2 - 0x07&lt;br /&gt;
0x1C AGCCTRL1 - 0x00&lt;br /&gt;
0x1D AGCCTRL0 - 0x91&lt;br /&gt;
0x1E WOREVT1  - 0x87&lt;br /&gt;
0x1F WOREVT0  - 0x6B&lt;br /&gt;
0x20 WORCTRL  - 0xF8&lt;br /&gt;
0x21 FREND1   - 0x56&lt;br /&gt;
0x22 FREND0   - 0x11&lt;br /&gt;
0x23 FSCAL3   - 0xEF&lt;br /&gt;
0x24 FSCAL2   - 0x2D&lt;br /&gt;
0x25 FSCAL1   - 0x12&lt;br /&gt;
0x26 FSCAL0   - 0x1F&lt;br /&gt;
0x27 RCCTRL1  - 0x41&lt;br /&gt;
0x28 RCCTRL0  - 0x00&lt;br /&gt;
0x29 FSTEST   - 0x59&lt;br /&gt;
0x2A PTEST    - 0x7F&lt;br /&gt;
0x2B AGCTEST  - 0x3F&lt;br /&gt;
0x2C TEST2    - 0x88&lt;br /&gt;
0x2D TEST1    - 0x31&lt;br /&gt;
0x2E TEST0    - 0x0B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;br /&gt;
[[Kategorie:868MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32244</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32244"/>
		<updated>2019-12-30T20:52:34Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Baudrate */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal.png|mini|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Fernbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Last but not least: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
Register-Settings:&lt;br /&gt;
&lt;br /&gt;
* Trägerfrequenz: 868.302 MHz&lt;br /&gt;
* Deviation: 25 kHz&lt;br /&gt;
* Bandwidth: 58 kHz&lt;br /&gt;
* Baudrate: 24.795 kBaud&lt;br /&gt;
* Modulation: GFSK&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ccregAll: &lt;br /&gt;
&lt;br /&gt;
ccreg 00: 0D 2E 2D 47 D3 91 3D 04 32 00 00 06 00 21 65 6F&lt;br /&gt;
ccreg 10: F9 F4 18 23 B9 40 07 00 18 14 6C 07 00 91 87 6B&lt;br /&gt;
ccreg 20: F8 56 11 EF 2D 12 1F 41 00 59 7F 3F 88 31 0B &lt;br /&gt;
&lt;br /&gt;
Configuration Register Detail (address, name, value):&lt;br /&gt;
0x00 IOCFG2   - 0x0D&lt;br /&gt;
0x01 IOCFG1   - 0x2E&lt;br /&gt;
0x02 IOCFG0   - 0x2D&lt;br /&gt;
0x03 FIFOTHR  - 0x47&lt;br /&gt;
0x04 SYNC1    - 0xD3&lt;br /&gt;
0x05 SYNC0    - 0x91&lt;br /&gt;
0x06 PKTLEN   - 0x3D&lt;br /&gt;
0x07 PKTCTRL1 - 0x04&lt;br /&gt;
0x08 PKTCTRL0 - 0x32&lt;br /&gt;
0x09 ADDR     - 0x00&lt;br /&gt;
0x0A CHANNR   - 0x00&lt;br /&gt;
0x0B FSCTRL1  - 0x06&lt;br /&gt;
0x0C FSCTRL0  - 0x00&lt;br /&gt;
0x0D FREQ2    - 0x21&lt;br /&gt;
0x0E FREQ1    - 0x65&lt;br /&gt;
0x0F FREQ0    - 0x6F&lt;br /&gt;
0x10 MDMCFG4  - 0xF9&lt;br /&gt;
0x11 MDMCFG3  - 0xF4&lt;br /&gt;
0x12 MDMCFG2  - 0x18&lt;br /&gt;
0x13 MDMCFG1  - 0x23&lt;br /&gt;
0x14 MDMCFG0  - 0xB9&lt;br /&gt;
0x15 DEVIATN  - 0x40&lt;br /&gt;
0x16 MCSM2    - 0x07&lt;br /&gt;
0x17 MCSM1    - 0x00&lt;br /&gt;
0x18 MCSM0    - 0x18&lt;br /&gt;
0x19 FOCCFG   - 0x14&lt;br /&gt;
0x1A BSCFG    - 0x6C&lt;br /&gt;
0x1B AGCCTRL2 - 0x07&lt;br /&gt;
0x1C AGCCTRL1 - 0x00&lt;br /&gt;
0x1D AGCCTRL0 - 0x91&lt;br /&gt;
0x1E WOREVT1  - 0x87&lt;br /&gt;
0x1F WOREVT0  - 0x6B&lt;br /&gt;
0x20 WORCTRL  - 0xF8&lt;br /&gt;
0x21 FREND1   - 0x56&lt;br /&gt;
0x22 FREND0   - 0x11&lt;br /&gt;
0x23 FSCAL3   - 0xEF&lt;br /&gt;
0x24 FSCAL2   - 0x2D&lt;br /&gt;
0x25 FSCAL1   - 0x12&lt;br /&gt;
0x26 FSCAL0   - 0x1F&lt;br /&gt;
0x27 RCCTRL1  - 0x41&lt;br /&gt;
0x28 RCCTRL0  - 0x00&lt;br /&gt;
0x29 FSTEST   - 0x59&lt;br /&gt;
0x2A PTEST    - 0x7F&lt;br /&gt;
0x2B AGCTEST  - 0x3F&lt;br /&gt;
0x2C TEST2    - 0x88&lt;br /&gt;
0x2D TEST1    - 0x31&lt;br /&gt;
0x2E TEST0    - 0x0B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;br /&gt;
[[Kategorie:868MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Datei:RIO-Signal.png&amp;diff=32243</id>
		<title>Datei:RIO-Signal.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Datei:RIO-Signal.png&amp;diff=32243"/>
		<updated>2019-12-30T20:51:43Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;RIO-Signal&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32242</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32242"/>
		<updated>2019-12-30T20:46:53Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Codesequenzen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal decodiert.png|mini|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Fernbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Last but not least: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
Register-Settings:&lt;br /&gt;
&lt;br /&gt;
* Trägerfrequenz: 868.302 MHz&lt;br /&gt;
* Deviation: 25 kHz&lt;br /&gt;
* Bandwidth: 58 kHz&lt;br /&gt;
* Baudrate: 24.795 kBaud&lt;br /&gt;
* Modulation: GFSK&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ccregAll: &lt;br /&gt;
&lt;br /&gt;
ccreg 00: 0D 2E 2D 47 D3 91 3D 04 32 00 00 06 00 21 65 6F&lt;br /&gt;
ccreg 10: F9 F4 18 23 B9 40 07 00 18 14 6C 07 00 91 87 6B&lt;br /&gt;
ccreg 20: F8 56 11 EF 2D 12 1F 41 00 59 7F 3F 88 31 0B &lt;br /&gt;
&lt;br /&gt;
Configuration Register Detail (address, name, value):&lt;br /&gt;
0x00 IOCFG2   - 0x0D&lt;br /&gt;
0x01 IOCFG1   - 0x2E&lt;br /&gt;
0x02 IOCFG0   - 0x2D&lt;br /&gt;
0x03 FIFOTHR  - 0x47&lt;br /&gt;
0x04 SYNC1    - 0xD3&lt;br /&gt;
0x05 SYNC0    - 0x91&lt;br /&gt;
0x06 PKTLEN   - 0x3D&lt;br /&gt;
0x07 PKTCTRL1 - 0x04&lt;br /&gt;
0x08 PKTCTRL0 - 0x32&lt;br /&gt;
0x09 ADDR     - 0x00&lt;br /&gt;
0x0A CHANNR   - 0x00&lt;br /&gt;
0x0B FSCTRL1  - 0x06&lt;br /&gt;
0x0C FSCTRL0  - 0x00&lt;br /&gt;
0x0D FREQ2    - 0x21&lt;br /&gt;
0x0E FREQ1    - 0x65&lt;br /&gt;
0x0F FREQ0    - 0x6F&lt;br /&gt;
0x10 MDMCFG4  - 0xF9&lt;br /&gt;
0x11 MDMCFG3  - 0xF4&lt;br /&gt;
0x12 MDMCFG2  - 0x18&lt;br /&gt;
0x13 MDMCFG1  - 0x23&lt;br /&gt;
0x14 MDMCFG0  - 0xB9&lt;br /&gt;
0x15 DEVIATN  - 0x40&lt;br /&gt;
0x16 MCSM2    - 0x07&lt;br /&gt;
0x17 MCSM1    - 0x00&lt;br /&gt;
0x18 MCSM0    - 0x18&lt;br /&gt;
0x19 FOCCFG   - 0x14&lt;br /&gt;
0x1A BSCFG    - 0x6C&lt;br /&gt;
0x1B AGCCTRL2 - 0x07&lt;br /&gt;
0x1C AGCCTRL1 - 0x00&lt;br /&gt;
0x1D AGCCTRL0 - 0x91&lt;br /&gt;
0x1E WOREVT1  - 0x87&lt;br /&gt;
0x1F WOREVT0  - 0x6B&lt;br /&gt;
0x20 WORCTRL  - 0xF8&lt;br /&gt;
0x21 FREND1   - 0x56&lt;br /&gt;
0x22 FREND0   - 0x11&lt;br /&gt;
0x23 FSCAL3   - 0xEF&lt;br /&gt;
0x24 FSCAL2   - 0x2D&lt;br /&gt;
0x25 FSCAL1   - 0x12&lt;br /&gt;
0x26 FSCAL0   - 0x1F&lt;br /&gt;
0x27 RCCTRL1  - 0x41&lt;br /&gt;
0x28 RCCTRL0  - 0x00&lt;br /&gt;
0x29 FSTEST   - 0x59&lt;br /&gt;
0x2A PTEST    - 0x7F&lt;br /&gt;
0x2B AGCTEST  - 0x3F&lt;br /&gt;
0x2C TEST2    - 0x88&lt;br /&gt;
0x2D TEST1    - 0x31&lt;br /&gt;
0x2E TEST0    - 0x0B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;br /&gt;
[[Kategorie:868MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32241</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32241"/>
		<updated>2019-12-30T20:46:08Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* SIGNALduino - FSK */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal decodiert.png|mini|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Ferndbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Last but not least: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
Register-Settings:&lt;br /&gt;
&lt;br /&gt;
* Trägerfrequenz: 868.302 MHz&lt;br /&gt;
* Deviation: 25 kHz&lt;br /&gt;
* Bandwidth: 58 kHz&lt;br /&gt;
* Baudrate: 24.795 kBaud&lt;br /&gt;
* Modulation: GFSK&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ccregAll: &lt;br /&gt;
&lt;br /&gt;
ccreg 00: 0D 2E 2D 47 D3 91 3D 04 32 00 00 06 00 21 65 6F&lt;br /&gt;
ccreg 10: F9 F4 18 23 B9 40 07 00 18 14 6C 07 00 91 87 6B&lt;br /&gt;
ccreg 20: F8 56 11 EF 2D 12 1F 41 00 59 7F 3F 88 31 0B &lt;br /&gt;
&lt;br /&gt;
Configuration Register Detail (address, name, value):&lt;br /&gt;
0x00 IOCFG2   - 0x0D&lt;br /&gt;
0x01 IOCFG1   - 0x2E&lt;br /&gt;
0x02 IOCFG0   - 0x2D&lt;br /&gt;
0x03 FIFOTHR  - 0x47&lt;br /&gt;
0x04 SYNC1    - 0xD3&lt;br /&gt;
0x05 SYNC0    - 0x91&lt;br /&gt;
0x06 PKTLEN   - 0x3D&lt;br /&gt;
0x07 PKTCTRL1 - 0x04&lt;br /&gt;
0x08 PKTCTRL0 - 0x32&lt;br /&gt;
0x09 ADDR     - 0x00&lt;br /&gt;
0x0A CHANNR   - 0x00&lt;br /&gt;
0x0B FSCTRL1  - 0x06&lt;br /&gt;
0x0C FSCTRL0  - 0x00&lt;br /&gt;
0x0D FREQ2    - 0x21&lt;br /&gt;
0x0E FREQ1    - 0x65&lt;br /&gt;
0x0F FREQ0    - 0x6F&lt;br /&gt;
0x10 MDMCFG4  - 0xF9&lt;br /&gt;
0x11 MDMCFG3  - 0xF4&lt;br /&gt;
0x12 MDMCFG2  - 0x18&lt;br /&gt;
0x13 MDMCFG1  - 0x23&lt;br /&gt;
0x14 MDMCFG0  - 0xB9&lt;br /&gt;
0x15 DEVIATN  - 0x40&lt;br /&gt;
0x16 MCSM2    - 0x07&lt;br /&gt;
0x17 MCSM1    - 0x00&lt;br /&gt;
0x18 MCSM0    - 0x18&lt;br /&gt;
0x19 FOCCFG   - 0x14&lt;br /&gt;
0x1A BSCFG    - 0x6C&lt;br /&gt;
0x1B AGCCTRL2 - 0x07&lt;br /&gt;
0x1C AGCCTRL1 - 0x00&lt;br /&gt;
0x1D AGCCTRL0 - 0x91&lt;br /&gt;
0x1E WOREVT1  - 0x87&lt;br /&gt;
0x1F WOREVT0  - 0x6B&lt;br /&gt;
0x20 WORCTRL  - 0xF8&lt;br /&gt;
0x21 FREND1   - 0x56&lt;br /&gt;
0x22 FREND0   - 0x11&lt;br /&gt;
0x23 FSCAL3   - 0xEF&lt;br /&gt;
0x24 FSCAL2   - 0x2D&lt;br /&gt;
0x25 FSCAL1   - 0x12&lt;br /&gt;
0x26 FSCAL0   - 0x1F&lt;br /&gt;
0x27 RCCTRL1  - 0x41&lt;br /&gt;
0x28 RCCTRL0  - 0x00&lt;br /&gt;
0x29 FSTEST   - 0x59&lt;br /&gt;
0x2A PTEST    - 0x7F&lt;br /&gt;
0x2B AGCTEST  - 0x3F&lt;br /&gt;
0x2C TEST2    - 0x88&lt;br /&gt;
0x2D TEST1    - 0x31&lt;br /&gt;
0x2E TEST0    - 0x0B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;br /&gt;
[[Kategorie:868MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32226</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32226"/>
		<updated>2019-12-30T12:37:44Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Codesequenzen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal decodiert.png|mini|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Ferndbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
=== Konfiguration ===&lt;br /&gt;
&lt;br /&gt;
Last but not least: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
Register-Settings:&lt;br /&gt;
&lt;br /&gt;
* Trägerfrequenz: 868.302 MHz&lt;br /&gt;
* Deviation: 25 kHz&lt;br /&gt;
* Bandwidth: 58 kHz&lt;br /&gt;
* Baudrate: 24.795 kBaud&lt;br /&gt;
* Modulation: GFSK&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ccregAll: &lt;br /&gt;
&lt;br /&gt;
ccreg 00: 0D 2E 2D 47 D3 91 3D 04 32 00 00 06 00 21 65 6F&lt;br /&gt;
ccreg 10: F9 F4 18 23 B9 40 07 00 18 14 6C 07 00 91 87 6B&lt;br /&gt;
ccreg 20: F8 56 11 EF 2D 12 1F 41 00 59 7F 3F 88 31 0B &lt;br /&gt;
&lt;br /&gt;
Configuration Register Detail (address, name, value):&lt;br /&gt;
0x00 IOCFG2   - 0x0D&lt;br /&gt;
0x01 IOCFG1   - 0x2E&lt;br /&gt;
0x02 IOCFG0   - 0x2D&lt;br /&gt;
0x03 FIFOTHR  - 0x47&lt;br /&gt;
0x04 SYNC1    - 0xD3&lt;br /&gt;
0x05 SYNC0    - 0x91&lt;br /&gt;
0x06 PKTLEN   - 0x3D&lt;br /&gt;
0x07 PKTCTRL1 - 0x04&lt;br /&gt;
0x08 PKTCTRL0 - 0x32&lt;br /&gt;
0x09 ADDR     - 0x00&lt;br /&gt;
0x0A CHANNR   - 0x00&lt;br /&gt;
0x0B FSCTRL1  - 0x06&lt;br /&gt;
0x0C FSCTRL0  - 0x00&lt;br /&gt;
0x0D FREQ2    - 0x21&lt;br /&gt;
0x0E FREQ1    - 0x65&lt;br /&gt;
0x0F FREQ0    - 0x6F&lt;br /&gt;
0x10 MDMCFG4  - 0xF9&lt;br /&gt;
0x11 MDMCFG3  - 0xF4&lt;br /&gt;
0x12 MDMCFG2  - 0x18&lt;br /&gt;
0x13 MDMCFG1  - 0x23&lt;br /&gt;
0x14 MDMCFG0  - 0xB9&lt;br /&gt;
0x15 DEVIATN  - 0x40&lt;br /&gt;
0x16 MCSM2    - 0x07&lt;br /&gt;
0x17 MCSM1    - 0x00&lt;br /&gt;
0x18 MCSM0    - 0x18&lt;br /&gt;
0x19 FOCCFG   - 0x14&lt;br /&gt;
0x1A BSCFG    - 0x6C&lt;br /&gt;
0x1B AGCCTRL2 - 0x07&lt;br /&gt;
0x1C AGCCTRL1 - 0x00&lt;br /&gt;
0x1D AGCCTRL0 - 0x91&lt;br /&gt;
0x1E WOREVT1  - 0x87&lt;br /&gt;
0x1F WOREVT0  - 0x6B&lt;br /&gt;
0x20 WORCTRL  - 0xF8&lt;br /&gt;
0x21 FREND1   - 0x56&lt;br /&gt;
0x22 FREND0   - 0x11&lt;br /&gt;
0x23 FSCAL3   - 0xEF&lt;br /&gt;
0x24 FSCAL2   - 0x2D&lt;br /&gt;
0x25 FSCAL1   - 0x12&lt;br /&gt;
0x26 FSCAL0   - 0x1F&lt;br /&gt;
0x27 RCCTRL1  - 0x41&lt;br /&gt;
0x28 RCCTRL0  - 0x00&lt;br /&gt;
0x29 FSTEST   - 0x59&lt;br /&gt;
0x2A PTEST    - 0x7F&lt;br /&gt;
0x2B AGCTEST  - 0x3F&lt;br /&gt;
0x2C TEST2    - 0x88&lt;br /&gt;
0x2D TEST1    - 0x31&lt;br /&gt;
0x2E TEST0    - 0x0B&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;br /&gt;
[[Kategorie:868MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32225</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32225"/>
		<updated>2019-12-30T10:48:08Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal decodiert.png|mini|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Ferndbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
Last but not least: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;br /&gt;
[[Kategorie:868MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32224</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32224"/>
		<updated>2019-12-30T10:45:00Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Codesequenzen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal decodiert.png|mini|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die mittels FSK empfangenen. Deshalb: Sequenzen mit der Original-Ferndbedienung neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Ab hier könnt Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dann erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt die Spreu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
Last but not least: SDUINO Firmware war die Version v3.4.1_dev_21.12&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32223</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32223"/>
		<updated>2019-12-30T10:42:10Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Baudrate */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal decodiert.png|mini|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/Symbol (Symbol=bit) ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die korrekt mittels FSK empfangenen. Deshalb: Sequenzen neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Hier könnte Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dan erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt dann die Sprecu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32222</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32222"/>
		<updated>2019-12-30T10:41:33Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Baudrate */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden:&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels &#039;&#039;get &amp;lt;myduino&amp;gt; ccconf&#039;&#039; ausgegebene Baudrate ist die zwischen dem Arduino und dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino den Signalpegel und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal decodiert.png|mini|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich im CC1101 nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts. Die SOftware URH arbeitet ähnlich. Das Signal wird z.B. mit 1 MHz gesampled. Um auf die ermittelte Baudrate und eine realse Darstellung zu kommen gebe ich 402 Samples/bit ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die korrekt mittels FSK empfangenen. Deshalb: Sequenzen neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Hier könnte Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dan erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt dann die Sprecu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32221</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32221"/>
		<updated>2019-12-30T10:37:45Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Hub einstellen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Hub ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels get &amp;lt;myduino&amp;gt; ccconf ausgegebene Baudrate ist die zwischen dem Arduino ind dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino das Signal und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal decodiert.png|mini|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die korrekt mittels FSK empfangenen. Deshalb: Sequenzen neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Hier könnte Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dan erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt dann die Sprecu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32220</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32220"/>
		<updated>2019-12-30T10:36:50Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* FSK Senden */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändert. Am einfachsten geht das über &lt;br /&gt;
&#039;&#039;get &amp;lt;mysduino&amp;gt; ccreg 99&#039;&#039;&lt;br /&gt;
Ihr müsst beim angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK statt OOK machen.&lt;br /&gt;
Das Register wird über &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1410&#039;&#039; &lt;br /&gt;
abgeändert (bitte beachtet das Offset von 0x02 für das Beschreiben eines Registers, 14 adressiert Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Hub einstellen ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch aktuell noch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels get &amp;lt;myduino&amp;gt; ccconf ausgegebene Baudrate ist die zwischen dem Arduino ind dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino das Signal und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal decodiert.png|mini|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die korrekt mittels FSK empfangenen. Deshalb: Sequenzen neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Hier könnte Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dan erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt dann die Sprecu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32219</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32219"/>
		<updated>2019-12-30T10:32:54Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Ermittlung der Frequenzen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch Vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz wird &amp;quot;relativ&amp;quot; genau gemessen. Was aber hilft ist ein Vergleich Original/Kopie. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehmt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die ist für die weiteren Aktivitäten relevant. Die Abweichung könnte Ihr in der URH-Software zur Frequenzkorrektur vorgeben, dann werden identische Werte angezeigt.&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Das die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändern. A, einfachtesn geht das über einen &lt;br /&gt;
get &amp;lt;mysduino&amp;gt; ccreg 99&lt;br /&gt;
Ihr müsst bei angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK machen.&lt;br /&gt;
Das Registzer wird über &lt;br /&gt;
set &amp;lt;mysduino&amp;gt; raw W1410 &lt;br /&gt;
abgeändert (bitte beachtet das offset von 0x02 für das Beschreiben eines Registers, 14 adressiert hier Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Hub einstellen ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch aktuell noch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels get &amp;lt;myduino&amp;gt; ccconf ausgegebene Baudrate ist die zwischen dem Arduino ind dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino das Signal und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal decodiert.png|mini|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die korrekt mittels FSK empfangenen. Deshalb: Sequenzen neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Hier könnte Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dan erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt dann die Sprecu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32218</id>
		<title>Unbekannte Funkprotokolle</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unbekannte_Funkprotokolle&amp;diff=32218"/>
		<updated>2019-12-30T10:30:59Z</updated>

		<summary type="html">&lt;p&gt;Plin53177: /* Sendefrequenz und Frequenzhub */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt jede Menge offiziell in FHEM unterstützte Devices und Funkprotokolle. Solange das Device Ross und Reiter benennt (Homematic, Z-Wave, Intertechno etc.) ist es einfach dieses in FHEM einzubinden. Was aber, wenn selbst mit hinreichend gut aktualisierter Installation nichts erkannt wird und es ein No-Name Produkt ist bei dem man nur die Hoffnung hat, dass es im Innern etwas Bekanntes beherbergt?&lt;br /&gt;
&lt;br /&gt;
Dieser Wiki-Artikel soll jenen helfen, die Geräte mit einem unbekannten Funkprotokoll an FHEM anbinden bzw. mit FHEM steuern wollen.&lt;br /&gt;
&lt;br /&gt;
Wenn hier drin irgendetwas unverständlich sein sollte (und wenn es nur deswegen sein sollte, weil es hinreichend bescheuert beschrieben ist :)), dann --&amp;gt; &amp;lt;big&amp;gt;&#039;&#039;&#039;MELDEN!&#039;&#039;&#039;&amp;lt;/big&amp;gt; (oder natürlich einfach verbessern) - die Usability dieses Projekts sollte sehr gut werden...&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel soll eine möglichst gut chronologische Sortierung haben, also:&lt;br /&gt;
&lt;br /&gt;
Einführung ... erste Schritte ... Tests ... Analyse ... stabiler Betrieb ... Verfeinerung / letzte Schritte (Expertise-Details).&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Neben den bekannten Hardware-Dongles gibt es Selbstbaulösungen in Form eines SIGNALduino, CUL oder JeeLink. &lt;br /&gt;
&lt;br /&gt;
Diese unterscheiden sich in verschiedener Hinsicht:&lt;br /&gt;
* Sendemodul (SIGNALduino/CUL -&amp;gt; CC1101; JeeLink -&amp;gt; RF12B) [https://de.wikipedia.org/wiki/Amplitudenumtastung]&lt;br /&gt;
* Modulationsverfahren (OOK, ASK/FSK)&lt;br /&gt;
* Frequenzband (433 MHz, 868 MHz)&lt;br /&gt;
&lt;br /&gt;
(bei SIGNALduino / CUL kann manche Hardware - z.B. nanoCUL - da hardware-kompatibel, mit Projektaktivitäten von CUL &#039;&#039;oder&#039;&#039; SIGNALduino betrieben/firmware-geflasht werden; evt. ist es sogar außerdem empfehlenswert, mehrere baugleiche Geräte zu haben, um SIGNALduino &#039;&#039;und&#039;&#039; CUL gleichzeitig verfügbar zu haben - evt. auch weitere Geräte mit unterschiedlichen Frequenzen: 433/868)&lt;br /&gt;
&lt;br /&gt;
==== Frequenzbereich ====&lt;br /&gt;
Für die funkbasierte Heimautomation kommen im Wesentlichen zwei Frequenzbänder in Frage: 433 und 868 MHz. Die meisten Geräte haben auf der Rückseite ein Typenschild, auf dem das Frequenzband ausgewiesen ist.&lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch 2,4 GHz (WLAN, Bluetooth, Funkmaus-Chipsätze...) und 5GHz (WLAN...), diese Frequenzbänder werden in diesem Artikel aber nicht betrachtet.&lt;br /&gt;
&lt;br /&gt;
==== Modulationsverfahren ====&lt;br /&gt;
&lt;br /&gt;
So, wie vom Rundfunk (AM/FM) her bekannt, kennt man auch bei 433/868 MHz verschiedene Modulationsverfahren. &lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Amplitudenumtastung OOK/ASK/Amplitudenabtastung]&lt;br /&gt;
: Das Signal des Senders wird auf der angegebenen Frequenz ein-/ausgeschaltet um die Dateninformationen zu übermitteln. &lt;br /&gt;
* [https://de.wikipedia.org/wiki/Frequenzumtastung FSK/Frequenzumtastung]&lt;br /&gt;
: Der Sender überträgt den Datenstrom indem, ausgehend von der Trägerfrequenz, zwischen Frequenzen (z.B. Frequenz-Frequenzhub, Frequenz+Frequenzhub) hin- und hergeschaltet wird. Dieses Verfahren kennt verschiedene Ausprägungen: 2-FSK, 4-FSK, GFSK (Details siehe [http://www.rfwireless-world.com/Terminology/2FSK-modulation-vs-4FSK-modulation.html hier]).&lt;br /&gt;
&lt;br /&gt;
==== Encoding oder auch Leitungscode ====&lt;br /&gt;
&lt;br /&gt;
Die Art und Weise wie dieses Signal interpretiert wird hängt wiederum vom Encoding ab. Dazu sei auf die nachfolgenden Quellen verwiesen.&lt;br /&gt;
&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Leitungscode Leitungscode (Einstieg)]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Non_Return_to_Zero NRZ]&lt;br /&gt;
* [https://de.wikipedia.org/wiki/Manchester-Code Manchester]&lt;br /&gt;
&lt;br /&gt;
Je nach verwendetem Encoding wird ggf. mehr als 1 Übertragungs-Bit für ein Datenbit benötigt. Der Empfänger erwartet z.B. einen Bitwechsel zu einem bestimmten Zeitpunkt. Eine Abfolge &lt;br /&gt;
* 100 (short high, long low) wird als 0&lt;br /&gt;
* 110 (long high, short low) wird als 1&lt;br /&gt;
interpretiert.&lt;br /&gt;
&lt;br /&gt;
Im FHEM-Forum gibt es viele freundliche Helfer die Euch bei Bedarf den richtigen Weg weisen.&lt;br /&gt;
&lt;br /&gt;
==== Signalstruktur ====&lt;br /&gt;
&lt;br /&gt;
Ein typischer Aufbau einer Signalstruktur sieht z.B. so aus&lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten |&lt;br /&gt;
&lt;br /&gt;
* eine größere Pause zur Trennung der Sequenzen &lt;br /&gt;
* ein Sync-Block mit dem sich der Empfänger auf den Sender einstellt&lt;br /&gt;
* eine Pause um Sync und Daten zu trennen&lt;br /&gt;
* die eigentlichen, zu übertragenden Daten.&lt;br /&gt;
&lt;br /&gt;
Es müssen nicht immer alle Bestandteile in der übertragenen Signalstruktur vorkommen (Details siehe auch [https://de.wikipedia.org/wiki/Datenpr%C3%A4ambel Datenpräambel] oder auch [https://en.wikipedia.org/wiki/Syncword Syncword]).&lt;br /&gt;
&lt;br /&gt;
Die Sequenz wird ggf. mehrfach wiederholt &lt;br /&gt;
&lt;br /&gt;
| Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | Pause | Sync | Pause | Daten | ...&lt;br /&gt;
&lt;br /&gt;
==== Protokoll ====&lt;br /&gt;
&lt;br /&gt;
Das ist der herstellerspezifische Teil des Signalstroms - die Daten. Hersteller haben i.d.R. ihre eigene Definition der übertragenen Datenströme. Teils werden feste Code-Sequenzen übertragen, es gibt aber auch rollierende Codes (Engl.: Rolling Codes) bei denen sich die Daten bei jeder Übertragung ändern (Fremd-Manipulations-Sicherheit). &lt;br /&gt;
&lt;br /&gt;
Mit etwas Glück erkennt z.B. SIGNALduino das Protokoll, damit den Hersteller und legt automatisch ein passendes Device in FHEM an. Manchmal gibt es auch Fehlinterpretationen und das vermeintlich bekannte Device entpuppt sich als etwas anderes (Statement aus dem Forum: &amp;quot;Lösung war, wo Dooya drauf steht muss nicht immer Dooya drin stecken.&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Wie fange ich an? ==&lt;br /&gt;
&lt;br /&gt;
==== Recherche ====&lt;br /&gt;
&lt;br /&gt;
Sucht im Internet nach Informationen zu dem fraglichen Device. Zu bekannten Devices sollten sich Informationen finden lassen, die einem weiter helfen. Solltet Ihr fündig werden, verfolgt die Hinweise, wie diese Devices in FHEM eingebunden werden können.&lt;br /&gt;
&lt;br /&gt;
Evt. haben auch konkrete verwandte Projekte bereits Protokoll-Informationen über das Gerät, z.B.:&lt;br /&gt;
* [https://github.com/merbanan/rtl_433/tree/master/src/devices rtl_433: Geräte-Verzeichnis]&lt;br /&gt;
&lt;br /&gt;
Wenn sich nichts Verwertbares finden lässt, geht&#039;s mit dem nächsten Abschnitt weiter.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 1 - Versuchen ====&lt;br /&gt;
&lt;br /&gt;
Einfach probieren: Bau Dir einen [[SIGNALduino]] für das passende Frequenzband (die 433 oder 868 MHz-Variante des CC1101). Stelle im SIGNALduino-Setting die Frequenz auf die genannte ein (durch den Befehl cc1101_freq = 433.000 oder 868.000) und die Bandbreite auf das Maximum (cc1101_bWidth = 325 kHz bzw. 650 kHz). Jetzt noch das Attribut verbose auf 5 setzen und dann das FHEM-log (tail -f fhem-yyyy-mm.log) beobachten.&lt;br /&gt;
&lt;br /&gt;
Ist ein Gerät in Reichweite, das regelmäßig etwas sendet (z.B. ein Funkthermometer), sollte hin und wieder etwas empfangen werden. Wenn &#039;&#039;autocreate&#039;&#039; aktiv ist, werden auf Basis der erkannten, bekannten Funkprotokolle automatisch neue Devices angelegt (dabei können auch diverse Funkthermometer der Nachbarschaft auftauchen).&lt;br /&gt;
&lt;br /&gt;
Ist es ein Gerät, das sich über eine Fernbedienung steuern lässt: Eine Taste betätigen und hoffen, dass sich im FHEM-Log etwas tut. Auch hier gilt: Handelt es sich um ein bekanntes Funkprotokoll, wird automatisch ein Device angelegt, allerdings nur eines für die Gerätefamilie. Bei Baumarkt-Funksteckdosen z.B. nur das erste gefundene. Die anderen müsst Ihr manuell anlegen und die entsprechenden Codes zur Identifikation der einzelnen Steckdosen anpassen (schaut z.B. hier nach: [[Intertechno_Code_Berechnung]]). &lt;br /&gt;
&lt;br /&gt;
Solltet Ihr mit diesem Ansatz Erfolg haben, ist das schon mal gut - Euer Gerät sendet ein bekanntes Protokoll und wird unterstützt.&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr etwas empfangen (MC, MS, MU), aber keine neuen Devices sehen, wird Euer Gerät möglicherweise noch nicht unterstützt. Jetzt gibt es zwei Varianten&lt;br /&gt;
* es handelt sich um ein neues, noch nicht bekanntes Protokoll -&amp;gt; postet einen Log-Ausschnitt auf [https://github.com/RFD-FHEM/RFFHEM/issues github] wie im [[SIGNALduino]]-Wiki vorgeschlagen)&lt;br /&gt;
* es handelt sich um etwas proprietäres, altes oder ähnlich kompliziertes (nicht aufgeben, weiterlesen)&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 2 - Aufschrauben ====&lt;br /&gt;
&lt;br /&gt;
Fernbedienung aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
Endgerät/Device aufschrauben, schauen welcher Chip dort verbaut ist.&lt;br /&gt;
&lt;br /&gt;
Das Teil ist zu klein? Folgende Möglichkeiten:&lt;br /&gt;
* so im Winkel gegen ein Lampenlicht halten, dass man die Schrift besonders gut lesen kann&lt;br /&gt;
* abfotografieren und das Foto vergrößern bis Ihr den Aufdruck lesen könnt&lt;br /&gt;
&lt;br /&gt;
Danach folgt dann Google und das Studium der zugehörigen Data Sheets der Chips.&lt;br /&gt;
&lt;br /&gt;
Das gibt Euch weitere Anhaltspunkte zum Modulationsverfahren, den Frequenzen und Optionen die die Chips unterstützen.&lt;br /&gt;
&lt;br /&gt;
Wenn die Grundsatzfrage geklärt ist, ergeben sich die ersten Handlungsoptionen&lt;br /&gt;
* OOK-Modulation -&amp;gt; [[SIGNALduino]]&lt;br /&gt;
* ASK/FSK -&amp;gt; [[Selbstbau_CUL]] oder [[JeeLink]]&lt;br /&gt;
&lt;br /&gt;
Die Devices senden/empfangen nicht notwendigerweise auf 433 oder 868 MHz, sondern auf Frequenzen &amp;quot;knapp daneben&amp;quot;, das kann z.B. bis zu 870 MHz hochgehen. Darüber, welche Frequenz es genau ist, gibt möglicherweise der verbaute Quarz Auskunft. Meist klein, silber mit einer Gravur wie z.B. 6,70 MHz versehen. Mit Hilfe der Spezifikationen im Datenblatt des daneben verbauten Chips lässt sich dann die Sende- bzw. Empfangsfrequenz errechnen.&lt;br /&gt;
&lt;br /&gt;
==== Ansatz 3 - Messen ====&lt;br /&gt;
&lt;br /&gt;
Ihr nutzt einen Spektrumanalysator. Es gibt verschiedene preisgünstige Ansätze. &lt;br /&gt;
&lt;br /&gt;
* Zum einen könnt Ihr den nrfmon-Ansatz verfolgen (siehe [https://jeelabs.net/projects/cafe/wiki/NRfMon_-_nano_Spectrum_Analyzer_with_the_RFM12B hier)]. Tipp: bestellt Euch direkt genug Material um zwei zu bauen, denn die RF12demo kann als Sender und Empfänger genutzt werden. Damit lässt sich direkt verifizieren, dass Euer RFM12B-Device wirklich sendet/empfängt.&lt;br /&gt;
* Der andere Ansatz nutzt einen DVB-T-Stick (siehe z.B. [https://homematic-forum.de/forum/viewtopic.php?t=11087 hier]. Es gibt aber viele Google-Treffer unter dem Stichwort [https://www.mikrocontroller.net/topic/243367 SDR]. Außerdem ein konkretes Projekt: [https://github.com/merbanan/rtl_433/ rtl_433].&lt;br /&gt;
* Mein persönlicher Favorit ist der [https://github.com/jopohl/urh Universal Radio Hacker]. Mit dem war ich in der Lage mittels RTL-SDR-Stick nicht nur Sequenzen mitzuschneiden sondern auch direkt zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Wieso überhaupt so kompliziert? OOK nutzt nur eine Frequenz, FSK zwei, vier, je nach Variante. Es kann auch vorkommen (so wie bei mir), dass ein FSK-Device auf einen OOK-Sender anspricht. Der Grund dafür sind Oberwellen die mit dem Ein-/Auschalten der Frequenz einher gehen.&lt;br /&gt;
&lt;br /&gt;
Die Spektrumanalyse gibt Aufschluss über&lt;br /&gt;
* das Modulationsverfahren (OOK vs. FSK) sowie&lt;br /&gt;
* die relevante(n) Frequenz(en)&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - OOK ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen SIGNALduino für alle weiteren Schritte nutzt.&lt;br /&gt;
&lt;br /&gt;
==== Log-Meldungen ====&lt;br /&gt;
&lt;br /&gt;
Der SIGNALduino empfängt die Rohdaten, ermittelt identische Zeitscheiben und ordnet diese den Zahlen 0-7 zu (P0...P7). Ein negativer Zahlenwert bedeutet &amp;quot;kein Empfang&amp;quot; und ein positiver &amp;quot;Signal empfangen&amp;quot;. Damit lässt sich der Datenstrom analysieren und für das Senden auch wieder generieren.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Pulslängen-Zahlen stehen für Mikrosekunden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was bedeutet D=012323...?&lt;br /&gt;
: 0 -&amp;gt; P0=-13020 =&amp;gt; 13.020 Mikrosekunden Pause&lt;br /&gt;
: 1 -&amp;gt; P1=15916 =&amp;gt; 15.916 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: 2 -&amp;gt; P2=-398 =&amp;gt; 398 Mikrosekunden Pause&lt;br /&gt;
: 3 -&amp;gt; P3=415 =&amp;gt; 415 Mikrosekunden Signal&lt;br /&gt;
: ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tip: um hier schnell zu einem guten Analyse-Ergebnis zu kommen, sind einige verfügbare Beispiel-Zeilen sinnvoll - hier könnte folgendes hilfreich sein:&lt;br /&gt;
Bei Geräten, die nicht on-demand (Knopfdruck) Funk-Aktivität generieren können:&lt;br /&gt;
Nicht langwierig auf das jeweils nächste verzögerte Intervall der Funk-Aktivität des Geräts warten, sondern stattdessen mehrfach die Geräte-Batterien erneut wieder einsetzen, so dass (hoffentlich) das Gerät immer eine erste Funk-Aktivität sendet, die:&lt;br /&gt;
* Log-Zeitstempelmäßig genau erkennbar ist&lt;br /&gt;
* hoffentlich immer gleich/ähnlich ist --&amp;gt; gute Analyse-Grundlage&lt;br /&gt;
Damit dürfte die Funk-Aktivität hinsichtlich Empfangsstärke, Trägerfrequenz etc. leichter festnagelbar sein.&lt;br /&gt;
&lt;br /&gt;
==== Frequenz ermitteln ====&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel geht davon aus, dass Ihr im 868 MHz-Band unterwegs seid. Bei 433 MHz könnt Ihr in gleicher Weise vorgehen.&lt;br /&gt;
&lt;br /&gt;
Fangt damit an, dass Ihr den CC101 mittels set-Command cc1101_freq auf 868.000, cc1101_bWidth auf 650 und cc11=1_sens auf 8 einstellt. Kontrollieren könnt Ihr das durch get ccconf. Die Bandbreite bWidth gibt an wie groß der Empfangsbereich ist. Bei 650 kHz sind das z.B. +/- 325 kHz, also der Bereich von 867.675 bis 868.325 MHz. &lt;br /&gt;
&lt;br /&gt;
Wenn ihr etwas empfangt ist das ein Ansatzpunkt. Anderfalls könnt Ihr die cc1101_freq in 200 kHz-Schritten (868.200, 868.400 ...) erhöhen und das Frequenzband auf diese Art und Weise absuchen. Ein Hinweis an der Stelle: Im FHEM-Log folgt bei den SIGNALduino-Einträgen nach dem Datenteil D= die Empfangsstärke R=. Damit könnt Ihr feststellen, ob Ihr Euch der Sendefrequenz nähert oder entfernt.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr nun Frequenzen gefunden habt bei denen Ihr etwas empfangt, dann könnt Ihr die bWidth jeweils halbieren und den Bereich, in dem etwas empfangen wurde, mit halbierter Frequenz-Schrittweite weiter durchforsten. Das macht Ihr so lange, bis bWidth bei 58 kHz angekommen ist. Damit sollte sich die gesuchte Trägerfrequenz herauskristallisieren.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Selektiver Empfang ====&lt;br /&gt;
&lt;br /&gt;
Am sichersten geht man selektiv vor - einen Message-Typ nach dem anderen testen. Im SIGNALduino kann man über das set-Command &amp;lt;code&amp;gt;disableMessagetype&amp;lt;/code&amp;gt; die Interpretation als MC, MS und MU selektiv ausschalten. Man kann mit MC beginnen und danach beobachten, ob es bei aktivem MS + MU Dekoder jeweils nur eine Art von Nachrichten gibt.&lt;br /&gt;
&lt;br /&gt;
Sobald man sieht, dass die Meldungen im FHEM-Log wechseln, die Message-Typen MS, MU bzw. MC mit nur einem aktiven Dekoder aufzeichnen.&lt;br /&gt;
&lt;br /&gt;
Das sollte Anhaltspunkte geben worauf der S&#039;duino am Besten reagiert.&lt;br /&gt;
&lt;br /&gt;
==== Eingrenzung - Log-Analyse via regex ====&lt;br /&gt;
&lt;br /&gt;
Wenn man schon ziemlich genau weiß, wie das Message-Pattern des relevanten Geräts aussieht, dann kann man sich folgendermaßen sehr elegant und schnell viele weitere zu diesem Gerät gehörige Aktivitäten aus dem Log fischen, ohne sehr störenden Traffic von anderen Geräten mit dabei zu haben:&lt;br /&gt;
z.B.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;tail -f log/fhem-2018-11.log|grep &amp;quot;sduino.*msg READ: .*=-4...;&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
um sich alle Pattern eines Geräts rauszufischen, bei dem man weiß, dass dessen Sende-Traffic das hinreichend charakteristische Merkmal besitzt, einen Low-Puls mit +- 4000us Länge zu haben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sduino433/msg READ: MU;P0=-956;P1=450;P2=-1987;P3=-4212;P4=96;P6=-304;D=01212121212121312131212131312121213131312131313431316;CP=1;R=224;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung: dies ist natürlich mit einem On-Demand-beherrschbaren Gerät (z.B. Fernbedienung, oder Batterie-basiertes Außerbetriebsetzen) kein Problem: hier kann man direkt live (aktueller Zeitpunkt!) nachvollziehen, ob die aktuelle Regex-Filterung tatsächlich Geräte-Aktivität richtig herausfischt (oder eben dummerweise nicht!). Jedoch bei nicht so leicht kontrollierbaren Geräten (intervall-mäßiges Senden, z.B. Klima-Sensoren, oder noch blöder, nur vereinzeltes Senden, z.B. Schwellwert-Sensoren, oder nicht direkt zugängliche Geräte) muss man natürlich den Regex möglichst wenig strikt formulieren, um sicherzustellen, dass man keine im Log abgelegte Aktivität dieses Geräts fälschlicherweise total übersieht/ignoriert.&lt;br /&gt;
&lt;br /&gt;
==== Variationen ====&lt;br /&gt;
&lt;br /&gt;
Solltet Ihr verschiedene Fernbedienungen für die Produktfamilie besitzen oder so wie ich eine die 8 Rolllädenmotoren bedienen kann, könnt Ihr bei nicht dokumentierten Protokollen trotzdem die Funktion der einzelnen Bytes herausarbeiten.&lt;br /&gt;
&lt;br /&gt;
Spielt jede Tastenkombination durch, extrahiert die Meldungen aus dem FHEM-Log und legt sie in separaten Dateien ab die ihr z.B. mit Motor, Richtung, Fernbedienung kennzeichnet.&lt;br /&gt;
&lt;br /&gt;
==== Signal analysieren ====&lt;br /&gt;
&lt;br /&gt;
Habt Ihr nun den Punkt erreicht an dem Ihr &#039;&#039;reproduzierbar&#039;&#039; (hinreichend stabil erfasste) (Teil-)Code-Sequenzen (oft in mehrfacher, identischer Wiederholung) im FHEM-Log seht, geht es ans Entschlüsseln. Auch hier wieder der einfache Fall: SIGNALduino kennt den Hersteller bzw. Device-Typ schon und legt automatisch ein FHEM-Device an (da das aber öfter nicht der Fall sein wird, muss man hier weiterarbeiten).&lt;br /&gt;
&lt;br /&gt;
Wenn ein Signal demoduliert wurde ist man den Bits und Bytes schon einen Schritt näher gekommen.&lt;br /&gt;
&lt;br /&gt;
Gehen wir wieder von unserem Beispiel aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-13020;P1=15916;P2=-398;P3=415;P4=4008;P5=-794;P6=812;D=01232323232323232323232324532653265353532653262653265326                                      26262626265353532653265326532653535326265353535353265353532653262653265353265353535353535353265326;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie ist diese Sequenz zu interpretieren?&lt;br /&gt;
&lt;br /&gt;
* Es startet mit einer Pause D=&#039;&#039;&#039;0&#039;&#039;&#039;123232323232&lt;br /&gt;
* gefolgt von einem Signal D=0&#039;&#039;&#039;1&#039;&#039;&#039;23232323232 in der Länge von ca. 16 ms.&lt;br /&gt;
* danach folgt ein Sync-Block D=01&#039;&#039;&#039;23232323232&#039;&#039;&#039;... bei dem jeweils Pärchen von 400 µs Pause/400 µs Signal wiederholt werden.&lt;br /&gt;
* Sync- und Datenteil sind durch einen Puls von 4 ms [P4=4008] getrennt D=0123232323232323232323232&#039;&#039;&#039;4&#039;&#039;&#039;53265&lt;br /&gt;
* gefolgt vom Datenteil D=01232323232323232323232324&#039;&#039;&#039;53265&#039;&#039;&#039;....&lt;br /&gt;
&lt;br /&gt;
Beim Datenteil wird es etwas komplizierter. Hier sind immer ein kurzer (2 oder 3) und ein langer (5 oder 6) Wert kombiniert. Folglich muss man bei der Interpretation zwischen Vorzeichen und Dauer differenzieren. Ein Pärchen ist immer 1.200 µs lang. In der Mitte dieser Zeitscheibe kann der übertragene Wert folglich eine Pause oder ein Signal sein.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Den Vorspann&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt; lassen wir mal außen vor und konzentrieren uns auf die Daten&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;53265326535326535326265353262653265353535326265353265326262653265326265353535353532653535353262653265353265353535353535353532626&lt;br /&gt;
&lt;br /&gt;
lSsLlSsLlSlSsLlSlSsLsLlSlSsLsLlSsLlSlSlSlSsLsLlSlSsLlSsLsLsLlSsLlSsLsLlSlSlSlSlSlSsLlSlSlSlSsLsLlSsLlSlSsLlSlSlSlSlSlSlSlSlSsLsL&lt;br /&gt;
&lt;br /&gt;
1 0 1 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 0&lt;br /&gt;
&lt;br /&gt;
10101101 10011001 01111001 10100010 10011111 10111100 10110111 11111100&lt;br /&gt;
&lt;br /&gt;
AD99 79A2 9FBC B7FC&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Analyse basiert auf folgenden Annahmen (mit Beispiels-Werten)&lt;br /&gt;
* Mapping von Puls-Werten auf logische Zustände: wenn 800-ter Pulse: Wert kleiner 0 (z.B. -800) ist ein l (long low), größer 0 ist L (long high), wenn 400-ter Pulse: analog, gemapped auf sS (short low/high) - &amp;quot;sSlL-Notation&amp;quot;...&lt;br /&gt;
* Weiter angenommen es werden immer 2 Frequenzen/Zustände verglichen (lS =&amp;gt; 1 und sL =&amp;gt; 0) (ein Gerät hat ja salopp gesagt nicht mehr zu tun als nur 2 Zustände - 0er und 1er Daten-Bits - robust codiert über Funk zu vermitteln - aus diesen Bits ergibt sich dann zusammengefügt ein gesamtes Geräte-Datenwort, welches anschließend in Bit-Bereiche wie Temperatur, Feuchte, Wind zerlegungs-analysiert werden muss, anhand charakteristischer Werte-Veränderungen, die man idealerweise auch direkt in z.B. einem Sensor-LCD-Display erkennen kann)&lt;br /&gt;
&lt;br /&gt;
Abseits-Bemerkung: Sollte man mit dem SIGNALduino ein &#039;&#039;FSK&#039;&#039;-Signal empfangen/interpretieren (im Gegensatz zu &amp;quot;normaleren&amp;quot; &#039;&#039;ASK&#039;&#039;, &#039;&#039;OOK&#039;&#039;), so hängt die Bewertung davon ab, ob man die Sendefrequenz+Frequenzhub oder Sendefrequenz-Frequenzhub empfängt. Die Bedeutung von 0/1 wird dann negiert. FIXME diese Beschreibung ist (mir) zu unklar, eine Verbesserung sollte erarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Weitere wichtige Tips:&lt;br /&gt;
* es ist wohl sinnvoll, zu versuchen, sich evt. an einem längsten Puls (das ist nämlich evt. eine Sync-Pause) zu orientieren, um nachfolgende Bereiche evt. als startendes Bit-Datenpaket identifizieren zu können&lt;br /&gt;
* man sollte die Pulsfolge per Textsuche analysieren, in einem Editor/Reader, der Such-Texte in einer Zeile &#039;&#039;&#039;mehrfach&#039;&#039;&#039; farbig markieren kann (less, ...) - bei markiertem Suchtreffer kann man dann Teil-Folgen identifizieren, welche sich deterministisch &#039;&#039;wiederholen&#039;&#039; - diese sind dann wohl offensichtlich codierte Bit-Daten, welche es passend zu entschlüsseln gilt&lt;br /&gt;
* die identifizierten Merkmale sind dann als ein neues Protokoll (falls kein bereits existierendes Protokoll zu unpräzise formuliert sein sollte!) in &amp;lt;code&amp;gt;FHEM/lib/signalduino_protocols.hash&amp;lt;/code&amp;gt; hinzuzufügen (Angabe präziser Durchschnittswerte von Basis-Takt, Gesamt-Patternlänge, Puls-Pause-Verhältnisse, ... - Details dieses Protokolls siehe Header dieser Datei), und dann muss ein &amp;quot;reload 00_SIGNALduino&amp;quot; gemacht werden, um dies zu testen (hier: beim sduino-Device temporär(!!) Attribute verbose 5 und debug 1 setzen!)&lt;br /&gt;
* für Beispiele einer Protokoll-Implementierung sollte man sich wohl auch die History (entsprechende Commits) im [[#Links|RFFHEM git repository]] ansehen&lt;br /&gt;
* es ist evt. sinnvoll, sich die Verarbeitungskette anhand von Empfang/Senden bereits funktionsfähiger Protokolle / Geräte zu verdeutlichen, bevor man selber loslegt, neue Geräte (Protokolle) zu unterstützen&lt;br /&gt;
* richtige Verarbeitung von empfangenen Funk-Pattern (oder in leicht abgeänderter Form derselben) kann man wohl besonders effizient debuggen, indem man sich einen Dummy-SIGNALduino anlegt:&lt;br /&gt;
&amp;lt;code&amp;gt;define sduino_dummy SIGNALduino none&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesen kann man dann die gewünschten zu unterstützenden Pattern einimpfen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;get sduino_dummy raw MC;;LL=-653;;LH=665;;SL=-317;;SH=348;;D=D55B58;;C=330;;L=21;;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle Strichpunkte (Semikolon) müssen hierbei jeweils escaped werden (durch Wiederholung), vermutlich da sie in FHEM&#039;s Perl-Code-Umgebung sonst als normale &#039;&#039;sequence points&#039;&#039; interpretiert würden.&lt;br /&gt;
&lt;br /&gt;
Weitere für einen Test verwendbare Beispiel-Pattern siehe [[#Links|RFFHEM git repository]], in Datei: &amp;lt;code&amp;gt;FHEM/14_SD_BELL.pm&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Wenn alles richtig läuft (weil man es richtig implementiert hat), dann sollte die gesamte Kette von Pattern-Fingerprinting bis hin zu Dispatch an Datenwort-Modul und dortige Verarbeitung bis hin zu einem entsprechend sichtbaren Auftauchen der Device-Aktivitäten/-Autocreate in FHEMWEB Event Monitor page und/oder Log durchlaufen werden.&lt;br /&gt;
&lt;br /&gt;
==== Steuern ====&lt;br /&gt;
&lt;br /&gt;
Die empfangenen, im Log ausgewiesenen Sequenzen könnt Ihr als Basis für das Senden verwenden. Relevant sind dabei Puls-Beschreibungen P0...P7 sowie D (Data). Die RSSI-Empfangsstärke wird beim Empfang als R= ausgewiesen. Beim Senden steht R jedoch für die Anzahl der Wiederholungen. Entnehmt die Details und Möglichkeiten bitte der Dokumentation [https://github.com/RFD-FHEM/SIGNALDuino/wiki/Commands Commands].&lt;br /&gt;
&lt;br /&gt;
==== Signal-Protokoll-Beschreibung verfeinern ====&lt;br /&gt;
&lt;br /&gt;
Sobald man bei einem Gerät initial erfolgreich empfangen / dekodieren (/ senden?) konnte, sollte man folgendes noch beachten:&lt;br /&gt;
&lt;br /&gt;
Es ist recht wichtig, dass jede Protokoll-Beschreibung eines Geräte-Signals &#039;&#039;&#039;möglichst präzise Geräte-konforme&#039;&#039;&#039; Werte aufführt:&lt;br /&gt;
&lt;br /&gt;
wenn mehrere Protokoll-Beschreibungen aufgrund von zu ungenauen Werten jeweils als passend betrachtet werden, dann&lt;br /&gt;
landet das Signal-Pattern (auch) bei falschen Protokoll-Beschreibungen - die weitere Zuordnung (dies ist eine Routing-Entscheidung!) hin zu spezifischen Geräte-Datenwort-FHEM-Modulen ist also gefährdet / sinnlos:&lt;br /&gt;
* evt. ganz fehlgeschlagen aufgrund von Falsch-Zuordnung&lt;br /&gt;
* viel sinnlose Noise im Log, weil gleich mehrere Pfade angeblich passen und dann &amp;quot;noch nicht supported&amp;quot;-Fehlermeldungen werfen&lt;br /&gt;
Mit stark steigender Anzahl von bekannten Protokoll-Beschreibungen dürfte dieses Problem immer schlimmer werden.&lt;br /&gt;
&lt;br /&gt;
Daher sollte man folgendes beachten:&lt;br /&gt;
* sicherstellen, dass nicht eine andere - also bereits existierende! - Protokoll-Beschreibung eigentlich die richtige gewesen wäre, welche nur aufgrund von Impräzisionen das aktuelle völlig Protokoll-gleiche Gerät NICHT erkannt hat (zudem: &amp;quot;ähnlich&amp;quot; aussehende Protokolle, die allerdings von klar unterschiedlichen Geräte-Familien erzeugt werden, sollten NICHT in der gleichen Protokoll-Beschreibung zusammengemischt werden, und man sollte diese Abgrenzung dort auch klarstellen: durch Referenz-Hinweise auf entsprechende fast gleiche Protokoll-Beschreibungen dort)&lt;br /&gt;
* &#039;&#039;length_min&#039;&#039; , &#039;&#039;length_max&#039;&#039; möglichst passend restriktiv spezifizieren (also z.B. 12 , 12)&lt;br /&gt;
* &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert möglichst präzise ermitteln&lt;br /&gt;
* ((die Perl-Demodulations-Implementierung - in &amp;lt;code&amp;gt;00_SIGNALduino.pm&amp;lt;/code&amp;gt; etc. - ebenfalls auf möglichst restriktive Checks / Wertebereiche trimmen))&lt;br /&gt;
&lt;br /&gt;
Ermittlung eines präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwerts dürfte folgendermaßen gut machbar sein:&lt;br /&gt;
* einige Geräte-Pattern aus dem Log fischen&lt;br /&gt;
* dort die &#039;&#039;clockabs&#039;&#039;-Werte suchen (&amp;lt;code&amp;gt;CP=x&amp;lt;/code&amp;gt; verweist darauf)&lt;br /&gt;
* aus diesen dann einen Mittelwert bilden, damit man die größte Präzision erreicht&lt;br /&gt;
* evt. sogar längere (Sync-)Pulse (z.B.: 15x &#039;&#039;clockabs&#039;&#039; Low, 1x &#039;&#039;clockabs&#039;&#039; High) heranziehen, um durch Mittelung (+ Teilung) über viele dieser z.B. 15x wiederholten Pulslängen einen daraus resultierend maximal präzisen &#039;&#039;clockabs&#039;&#039;-Basistakt-Mittelwert zu ermitteln&lt;br /&gt;
* evt. ist es auch hilfreich, den im Gerät verbauten Quartz zu berücksichtigen - u.U. lässt sich hieraus (falls eine solche Verarbeitung im Gerät tatsächlich Timer-mäßig relevant sein sollte!) ein sehr präziser da &amp;quot;mechanisch&amp;quot; passender Puls-Takt-Wert ermitteln (Pseudo-Beispiel:&lt;br /&gt;
&amp;lt;code&amp;gt;(1 / 8MHz) * 2048 [digitaler Teiler] = 0.256ms == 256us&amp;lt;/code&amp;gt;&lt;br /&gt;
); wobei der mechanische Gerätetakt evt. doch erstaunlich anders sein könnte als die von SIGNALduino erfassten Werte (inwiefern das dann hinsichtlich Rx-/Tx-Präzision relevant ist - wer weiß...)&lt;br /&gt;
&lt;br /&gt;
==== Development / patch submission ====&lt;br /&gt;
&lt;br /&gt;
Es ist evt. empfehlenswert, auf github einen eigenen Fork des RFFHEM-Upstream-Repositories zu erstellen - dann kann man &#039;&#039;dort&#039;&#039; seine Entwicklung durchführen:&lt;br /&gt;
* Änderungen durchführen (im korrekten Branch)&lt;br /&gt;
* &amp;lt;code&amp;gt;controls_signalduino.txt&amp;lt;/code&amp;gt; updaten (via &amp;lt;code&amp;gt;build_controls_list.sh&amp;lt;/code&amp;gt;), sonst werden die Änderungen nicht angenommen!&lt;br /&gt;
* alles committen&lt;br /&gt;
* mit dem üblichen FHEM-Befehl (&amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt;, aber eben sinnigerweise unter Angabe der URL seines &#039;&#039;eigenen&#039;&#039; Repositories!!) seine eigenen Änderungen jeweils korrekt verwaltend und updatend austesten&lt;br /&gt;
* evt. hier jeweils &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; nötig&lt;br /&gt;
* wenn das alles passt, hat man bereits seinen eigenen Fork fix und fertig (und authentisch getestet) und kann somit direkt - evt. nach einem bereinigenden &amp;lt;code&amp;gt;git rebase -i @{u}&amp;lt;/code&amp;gt; - einen Pull Request daraus machen (anders ausgedrückt: &amp;quot;direkt kontext-integrierte Entwicklung&amp;quot;, &amp;quot;am Puls der Zeit&amp;quot;, &amp;quot;mit voller Tool-Unterstützung&amp;quot;). Dies am besten vollständig Automatisierungs-gekapselt durch ein Shell-Script (FIXME: am besten hier einfach direkt hier präsentieren?), welches an FHEM den &amp;lt;code&amp;gt;update all ...&amp;lt;/code&amp;gt; request schickt (über telnet, Port 7072) &#039;&#039;und&#039;&#039; den &amp;lt;code&amp;gt;reload BEARBEITETES_MODUL&amp;lt;/code&amp;gt; durchführt.&lt;br /&gt;
&lt;br /&gt;
== SIGNALduino - FSK ==&lt;br /&gt;
&lt;br /&gt;
Aktuell laufen Bestrebungen den SIGNALduino FSK-fähig zu machen: siehe [https://forum.fhem.de/index.php/topic,106582.0.html FSK mit SIGNALduino] (vormals https://forum.fhem.de/index.php/topic,82379.0.html)&lt;br /&gt;
&lt;br /&gt;
Die Summary der CC1101-Settings findet ihr [https://forum.fhem.de/index.php/topic,106594.0.html#new hier].&lt;br /&gt;
&lt;br /&gt;
=== Sendefrequenz und Frequenzhub ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakLow.png|mini|ohne|300px|FSK, Trägerfrequenz minus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tright&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:PeakHigh.png|mini|links|300px|FSK, Trägerfrequenz plus Hub]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei OOK wird das Funksignal ein- und ausgeschaltet, um die bits als 0 und 1 darzustellen. Bei FSK sieht das anders aus. Zur Übertragung wird ein permanentes Signal ausgestrahlt; die Darstellung der bits 0 und 1 erfolgt durch Erniedrigung bzw. Erhöhung der Frequenz. Folglich gilt es sowohl die Trägerfrequenz als auch den Frequenzhub zu ermitteln. Das bit 0 wird i.d.R. durch Trägerfrequenz minus Hub, das bit 1 durch Trägerfrequenz plus Hub dargestellt.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielspektrum eines FSK-Signals ist ersichtlich, dass die untere Frequenz bei ca. 868,233 Mhz und die obere bei ca. 868,281 Mhz liegt. Die Trägerfrequenz liegt folglich in der Mitte bei 868,257 MHz und der Frequenzhub beträgt ca. 24 kHz.&lt;br /&gt;
&lt;br /&gt;
=== Ermittlung der Frequenzen ===&lt;br /&gt;
&lt;br /&gt;
Wie im OOK-Kapitel bereits angesprochen ist eine Messung mit Hilfe eines SDR-Sticks hilfreich. Doch vorsicht - diese Sticks sind oftmals nicht geeicht und die angezeigte Frequenz ist &amp;quot;relativ&amp;quot; gut gemessen. Was aber hilt ist ein Vergleich Original/Fälschung. Messt mit dem SDR-Stick unter Nutzung eines Programms wie URH die  Frequenzen, sendet mit dem SDUINO ebenfalls ein Signal auf einer von Euch vorgegebenen Frequenz. Nehemt als Basis für den Ver- bzw. Abgleich die von Euch im SDUINO vorgebene Frequenz. Die Abweichung könnte Ihr dann in der URH-Software zur Frequenzkorrektur vorgeben..&lt;br /&gt;
&lt;br /&gt;
=== FSK Senden ===&lt;br /&gt;
&lt;br /&gt;
Das die ersten Bits des CC1101-Register 12 MDMCFG2 bestimmen die Übertragungsweise:&lt;br /&gt;
000 = 2-FSK&lt;br /&gt;
001 = GFSK&lt;br /&gt;
011 = ASK/OOK&lt;br /&gt;
100 = 4-FSK&lt;br /&gt;
&lt;br /&gt;
Schaut Euch den aktuellen Registerinhalt an, bevor Ihr ihn ändern. A, einfachtesn geht das über einen &lt;br /&gt;
get &amp;lt;mysduino&amp;gt; ccreg 99&lt;br /&gt;
Ihr müsst bei angezeigten Wert die ersten drei Bits entsprechend abändern, also z.B. aus 0x30 dann 0x10 für GFSK machen.&lt;br /&gt;
Das Registzer wird über &lt;br /&gt;
set &amp;lt;mysduino&amp;gt; raw W1410 &lt;br /&gt;
abgeändert (bitte beachtet das offset von 0x02 für das Beschreiben eines Registers, 14 adressiert hier Register 12).&lt;br /&gt;
&lt;br /&gt;
Nun könnt Ihr FSK senden. Das im URH angezeigte Spektrum sollte nun zwei Spitzen aufweisen. Ihr seht daneben vermutlich auch weitere kleine links und rechts daneben. Das liegt daran, dass es Oberwellen gibt. Bei 2-FSK sind dies mehr als bei dem geglätteten GFSK.&lt;br /&gt;
&lt;br /&gt;
=== Hub einstellen ===&lt;br /&gt;
&lt;br /&gt;
Da hilft Euch aktuell noch das RF Studio für den CC1101. Der darin ermittelte Wert ist in das Register 15 DEVIATN zu übertragen. Bei 25 kHz Hub ist das der Wert 40 der mittels &lt;br /&gt;
&#039;&#039;set &amp;lt;mysduino&amp;gt; raw W1740&#039;&#039;&lt;br /&gt;
an den CC1101 des SDUINO übermittelt wird.&lt;br /&gt;
&lt;br /&gt;
Wenn Ihr soweit seid, sollten die Funksignale der Original-Fernbedienung und Eures SDUINO ähneln.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:RIO FB-Signal.png|mini|Spektrum Original-Fernbedienung]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:none&amp;quot;&amp;gt;[[Datei:Signal des SDUINO GFSK .png|mini|Spektrum SDUINO GFSK ]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Baudrate ===&lt;br /&gt;
&lt;br /&gt;
Beim SDUINO übernimmt der CC1101 die Funktion eines Modems. Die Signalaufbereitung bzw. -erzeugung erfolgt im Arduino. Das können wir auch für das Senden von FSK Signalen nutzen. Der CC1101 bietet ein Fülle weiterer Optionen (Sync, FIFO etc.) die aber eher für Spezialisten geeignet sind.&lt;br /&gt;
&lt;br /&gt;
Welche Baudrate soll/muss ich angeben? Zunächst mal gilt es folgende Teilstrecken zu unterscheiden&lt;br /&gt;
FHEM &amp;lt;-&amp;gt; Arduino &amp;lt;-&amp;gt; CC1101 &amp;lt;-&amp;gt; Sendesignal&lt;br /&gt;
&lt;br /&gt;
Die Baudrate zwischen FHEM und dem Arduino wird in FHEM vorgegeben. Die für den CC1101 angegebene und mittels get &amp;lt;myduino&amp;gt; ccconf ausgegebene Baudrate ist die zwischen dem Arduino ind dem CC1101. Mit dieser Baudrate wird das Funksignal gesampled.&lt;br /&gt;
&lt;br /&gt;
Beim Empfang interpretiert der Arduino das Signal und erkennt die Übergänge zwischen 0 und 1. Es wird die Dauer des jeweiligen Signals ermittels und einem Parameter 0-7 zugeordnet. Auf diese Weise wird die gesamte empfangene Codesequenz beschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:RIO-Signal decodiert.png|mini|RIO-Signal decodiert]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Baudrate lässt sich nur bedingt präzise einstellen, da dafür nur ein Byte zur Verfügung steht.&lt;br /&gt;
&lt;br /&gt;
Ich habe bei der obigen Sequenz die Baudrate bzw. SCLK aus dem Vorspann (Preamble) ermittelt und bin auf 2.482 Baud gekommen. Für die Übertragung habe ich aber die 10fache Rate verwendet, um die Steuerung des Zustandes 0/1 dem Arduino und nicht dem CC1101 zu überlassen. Statt einer 0 werden dann halt 10x 0 übertragen. Auf Sendeseite ändert sich dadurch nichts.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tleft&amp;quot; style=&amp;quot;clear:both&amp;quot;&amp;gt;[[Datei:Vergleich RIO-SDUINO-Signale.png|mini|Vergleich RIO/SDUINO-Signale]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear:both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Codesequenzen ===&lt;br /&gt;
Die Interpretaion des low und high-Zustandes hängt von der Sende- und Empfangsfrequenz ab. Wenn Ihr im OOK-Modus Sequenzen mitgeschnitten habt werden die möglicherweise anderes interpretiert als die korrekt mittels FSK empfangenen. Deshalb: Sequenzen neu erzeugen und mitschneiden. Achtet dabei darauf, dass diese lang genug sind, um das komplette Steuerungssignal mitzuschneiden. Die Preamble ist recht auffällig (bei mir 01232323 ...). Die wiederholt sich nach dem eigentlichen Steuerungssignal. Hier könnte Ihr also abschneiden. Ferner empfiehlt sich das mitgeschnittene Signal zu dekodieren und in Hex darzustellen. Dan erkennt Ihr, ob identische Inhalte/Sequenzen mitgeschnitten wurden. Das trennt dann die Sprecu vom Weizen. &lt;br /&gt;
&lt;br /&gt;
Damit konnte ich mein Problem meines unbekannten Funkprotokolls (RIO-Fernbedienung) letztendlich lösen.&lt;br /&gt;
&lt;br /&gt;
== CUL - FSK und Co. ==&lt;br /&gt;
&lt;br /&gt;
Dieses Kapitel geht davon aus, dass ihr einen CUL für alle weiteren Schritte nutzt. &lt;br /&gt;
&lt;br /&gt;
Es befindet sich aber noch im Aufbau....&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
=== Woran genau wird erkannt ob ein Signal ShortHigh, bzw ShortLow ist? ===&lt;br /&gt;
&lt;br /&gt;
Diese Begriffe kommen nur bei der Manchester Codierung zum Einsatz.&lt;br /&gt;
&lt;br /&gt;
Die Bestimmung short High / Low erfolgt einfach dadurch ob gesendet wird oder ob gerade eine Pause eingelegt wird.&lt;br /&gt;
&lt;br /&gt;
Short und Long wird einfach durch die Kalkulation der Dauer ermittelt.&lt;br /&gt;
&lt;br /&gt;
Die Dauer eines short Intervalles ist in der Regel halb so lang wie die von einem long und entspricht der Taktrate.&lt;br /&gt;
Bei der ganzen Berechnung müssen natürlich Toleranzen berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel einer empfangenen Sequenz&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;P0=-32001;P1=15874;P2=-364;P3=447;P4=4060;P5=-762;P6=853;D=01232323232323232323232324&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
P0, P2 + P5 haben ein negatives Vorzeichen. Damit ist gemeint, dass für eine Zeit von 762µs (P5) kein Signal empfangen wurde (Low). Die positiven sind dann High.&lt;br /&gt;
&lt;br /&gt;
Generell sind die absoluten, gemessenen low-Werte bei Signalduino kürzer als die high-Werte.&lt;br /&gt;
&lt;br /&gt;
Wie bereits ausgeführt, werden für die Daten die Pulse P2, P3, P5 und P6 genutzt. Der Mittelwert [ (P2 + P3 + P5 + P6) / 6 ] der absoluten Werte ergibt 404µs für ein Short und 808µs ein Long (2xShort). Idealisiert werden 400µs angenommen.&lt;br /&gt;
&lt;br /&gt;
Das Umwandeln der Pulse in den Daten in eine &amp;quot;sSlL-Notation&amp;quot; vereinfacht die Erkennung von Mustern (in mehreren Nachrichten variieren auch die Pulse).&lt;br /&gt;
Dass ein lS=1 und sL=0 entspricht, ist nur eine willkürlich angenommene Arbeitshypothese, die bis dato ganz gute Ergebnisse produziert hat.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/RFD-FHEM/RFFHEM RFFHEM git repository] (drandenken: korrekten Branch auswählen!)&lt;br /&gt;
* [https://www.hamspirit.de/2286/signalanalyse-fuer-dummies/ Signalanalyse für Dummies]&lt;br /&gt;
* [https://github.com/jopohl/urh Universal Radio Hacker]&lt;br /&gt;
* [https://www.elttam.com.au/blog/intro-sdr-and-rf-analysis/ Intro SDR and RF Analysis]&lt;br /&gt;
* [https://www.sigidwiki.com/wiki/Signal_Identification_Guide Signal Identification Guide]&lt;br /&gt;
* [https://www.rtl-sdr.com/tag/fsk/ Unknown Signal Reverse Engineering and Decoding AFSK Signals Tutorial]&lt;br /&gt;
* [[Intertechno Code Berechnung]]&lt;br /&gt;
* [[Funksignalanalyse mit DVB-T Stick]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Intertechno]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:433MHz]]&lt;/div&gt;</summary>
		<author><name>Plin53177</name></author>
	</entry>
</feed>